Skip to content

Commit f737043

Browse files
authored
Merge pull request #38969 from nkcsgexi/abi-checker-refactor
ABIChecker: minor refactoring to move code to APIDigester lib. NFC
2 parents 2fad626 + 35cb97b commit f737043

File tree

5 files changed

+328
-315
lines changed

5 files changed

+328
-315
lines changed

include/swift/APIDigester/ModuleAnalyzerNodes.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "clang/Sema/Lookup.h"
2424
#include "clang/Sema/Sema.h"
2525
#include "llvm/ADT/TinyPtrVector.h"
26+
#include "llvm/ADT/STLExtras.h"
2627
#include "llvm/Support/CommandLine.h"
2728
#include "llvm/Support/Compiler.h"
2829
#include "llvm/Support/FileSystem.h"
@@ -787,6 +788,8 @@ class SwiftDeclCollector: public VisibleDeclConsumer {
787788
void lookupVisibleDecls(ArrayRef<ModuleDecl *> Modules);
788789
};
789790

791+
void detectRename(SDKNode *L, SDKNode *R);
792+
790793
int dumpSwiftModules(const CompilerInvocation &InitInvok,
791794
const llvm::StringSet<> &ModuleNames,
792795
StringRef OutputDir,
@@ -805,6 +808,8 @@ int dumpSDKContent(const CompilerInvocation &InitInvok,
805808
const llvm::StringSet<> &ModuleNames,
806809
StringRef OutputFile, CheckerOptions Opts);
807810

811+
void dumpModuleContent(ModuleDecl *MD, StringRef OutputFile, bool ABI);
812+
808813
/// Mostly for testing purposes, this function de-serializes the SDK dump in
809814
/// dumpPath and re-serialize them to OutputPath. If the tool performs correctly,
810815
/// the contents in dumpPath and OutputPath should be identical.

lib/APIDigester/ModuleAnalyzerNodes.cpp

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,6 +2294,22 @@ int swift::ide::api::deserializeSDKDump(StringRef dumpPath, StringRef OutputPath
22942294
return 0;
22952295
}
22962296

2297+
void swift::ide::api::dumpModuleContent(ModuleDecl *MD, StringRef OutputFile,
2298+
bool ABI) {
2299+
CheckerOptions opts;
2300+
opts.ABI = ABI;
2301+
opts.SwiftOnly = true;
2302+
opts.AvoidLocation = true;
2303+
opts.AvoidToolArgs = true;
2304+
opts.Migrator = false;
2305+
opts.SkipOSCheck = false;
2306+
opts.Verbose = false;
2307+
SDKContext ctx(opts);
2308+
SwiftDeclCollector collector(ctx);
2309+
collector.lookupVisibleDecls({MD});
2310+
dumpSDKRoot(collector.getSDKRoot(), OutputFile);
2311+
}
2312+
22972313
int swift::ide::api::findDeclUsr(StringRef dumpPath, CheckerOptions Opts) {
22982314
std::error_code EC;
22992315
if (!fs::exists(dumpPath)) {
@@ -2323,3 +2339,301 @@ int swift::ide::api::findDeclUsr(StringRef dumpPath, CheckerOptions Opts) {
23232339
}
23242340
return 0;
23252341
}
2342+
2343+
void swift::ide::api::SDKNodeDeclType::diagnose(SDKNode *Right) {
2344+
SDKNodeDecl::diagnose(Right);
2345+
auto *R = dyn_cast<SDKNodeDeclType>(Right);
2346+
if (!R)
2347+
return;
2348+
auto Loc = R->getLoc();
2349+
if (getDeclKind() != R->getDeclKind()) {
2350+
emitDiag(Loc, diag::decl_kind_changed, getDeclKindStr(R->getDeclKind(),
2351+
getSDKContext().getOpts().CompilerStyle));
2352+
return;
2353+
}
2354+
2355+
assert(getDeclKind() == R->getDeclKind());
2356+
auto DKind = getDeclKind();
2357+
switch (DKind) {
2358+
case DeclKind::Class: {
2359+
auto LSuperClass = getSuperClassName();
2360+
auto RSuperClass = R->getSuperClassName();
2361+
if (!LSuperClass.empty() && LSuperClass != RSuperClass) {
2362+
if (RSuperClass.empty()) {
2363+
emitDiag(Loc, diag::super_class_removed, LSuperClass);
2364+
} else if (!llvm::is_contained(R->getClassInheritanceChain(), LSuperClass)) {
2365+
emitDiag(Loc, diag::super_class_changed, LSuperClass, RSuperClass);
2366+
}
2367+
}
2368+
2369+
// Check for @_hasMissingDesignatedInitializers and
2370+
// @_inheritsConvenienceInitializers changes.
2371+
if (isOpen() && R->isOpen()) {
2372+
// It's not safe to add new, invisible designated inits to open
2373+
// classes.
2374+
if (!hasMissingDesignatedInitializers() &&
2375+
R->hasMissingDesignatedInitializers())
2376+
R->emitDiag(R->getLoc(), diag::added_invisible_designated_init);
2377+
}
2378+
2379+
// It's not safe to stop inheriting convenience inits, it changes
2380+
// the set of initializers that are available.
2381+
if (!Ctx.checkingABI() &&
2382+
inheritsConvenienceInitializers() &&
2383+
!R->inheritsConvenienceInitializers())
2384+
R->emitDiag(R->getLoc(), diag::not_inheriting_convenience_inits);
2385+
break;
2386+
}
2387+
default:
2388+
break;
2389+
}
2390+
}
2391+
2392+
void swift::ide::api::SDKNodeDeclAbstractFunc::diagnose(SDKNode *Right) {
2393+
SDKNodeDecl::diagnose(Right);
2394+
auto *R = dyn_cast<SDKNodeDeclAbstractFunc>(Right);
2395+
if (!R)
2396+
return;
2397+
auto Loc = R->getLoc();
2398+
if (!isThrowing() && R->isThrowing()) {
2399+
emitDiag(Loc, diag::decl_new_attr, Ctx.buffer("throwing"));
2400+
}
2401+
if (Ctx.checkingABI()) {
2402+
if (reqNewWitnessTableEntry() != R->reqNewWitnessTableEntry()) {
2403+
emitDiag(Loc, diag::decl_new_witness_table_entry, reqNewWitnessTableEntry());
2404+
}
2405+
}
2406+
}
2407+
2408+
void swift::ide::api::SDKNodeDeclFunction::diagnose(SDKNode *Right) {
2409+
SDKNodeDeclAbstractFunc::diagnose(Right);
2410+
auto *R = dyn_cast<SDKNodeDeclFunction>(Right);
2411+
if (!R)
2412+
return;
2413+
auto Loc = R->getLoc();
2414+
if (getSelfAccessKind() != R->getSelfAccessKind()) {
2415+
emitDiag(Loc, diag::func_self_access_change, getSelfAccessKind(),
2416+
R->getSelfAccessKind());
2417+
}
2418+
if (Ctx.checkingABI()) {
2419+
if (hasFixedBinaryOrder() != R->hasFixedBinaryOrder()) {
2420+
emitDiag(Loc, diag::func_has_fixed_order_change, hasFixedBinaryOrder());
2421+
}
2422+
}
2423+
}
2424+
2425+
static StringRef getAttrName(DeclAttrKind Kind) {
2426+
switch (Kind) {
2427+
#define DECL_ATTR(NAME, CLASS, ...) \
2428+
case DAK_##CLASS: \
2429+
return DeclAttribute::isDeclModifier(DAK_##CLASS) ? #NAME : "@"#NAME;
2430+
#include "swift/AST/Attr.def"
2431+
case DAK_Count:
2432+
llvm_unreachable("unrecognized attribute kind.");
2433+
}
2434+
llvm_unreachable("covered switch");
2435+
}
2436+
2437+
static bool shouldDiagnoseAddingAttribute(SDKNodeDecl *D, DeclAttrKind Kind) {
2438+
return true;
2439+
}
2440+
2441+
static bool shouldDiagnoseRemovingAttribute(SDKNodeDecl *D, DeclAttrKind Kind) {
2442+
return true;
2443+
}
2444+
2445+
static bool isOwnershipEquivalent(ReferenceOwnership Left,
2446+
ReferenceOwnership Right) {
2447+
if (Left == Right)
2448+
return true;
2449+
if (Left == ReferenceOwnership::Unowned && Right == ReferenceOwnership::Weak)
2450+
return true;
2451+
if (Left == ReferenceOwnership::Weak && Right == ReferenceOwnership::Unowned)
2452+
return true;
2453+
return false;
2454+
}
2455+
2456+
void swift::ide::api::detectRename(SDKNode *L, SDKNode *R) {
2457+
if (L->getKind() == R->getKind() && isa<SDKNodeDecl>(L) &&
2458+
L->getPrintedName() != R->getPrintedName()) {
2459+
L->annotate(NodeAnnotation::Rename);
2460+
L->annotate(NodeAnnotation::RenameOldName, L->getPrintedName());
2461+
L->annotate(NodeAnnotation::RenameNewName, R->getPrintedName());
2462+
}
2463+
}
2464+
2465+
void swift::ide::api::SDKNodeDecl::diagnose(SDKNode *Right) {
2466+
SDKNode::diagnose(Right);
2467+
auto *RD = dyn_cast<SDKNodeDecl>(Right);
2468+
if (!RD)
2469+
return;
2470+
detectRename(this, RD);
2471+
auto Loc = RD->getLoc();
2472+
if (isOpen() && !RD->isOpen()) {
2473+
emitDiag(Loc, diag::no_longer_open);
2474+
}
2475+
2476+
// Diagnose static attribute change.
2477+
if (isStatic() ^ RD->isStatic()) {
2478+
emitDiag(Loc, diag::decl_new_attr, Ctx.buffer(isStatic() ? "not static" :
2479+
"static"));
2480+
}
2481+
2482+
// Diagnose ownership change.
2483+
if (!isOwnershipEquivalent(getReferenceOwnership(),
2484+
RD->getReferenceOwnership())) {
2485+
auto getOwnershipDescription = [&](swift::ReferenceOwnership O) {
2486+
if (O == ReferenceOwnership::Strong)
2487+
return Ctx.buffer("strong");
2488+
return keywordOf(O);
2489+
};
2490+
emitDiag(Loc, diag::decl_attr_change,
2491+
getOwnershipDescription(getReferenceOwnership()),
2492+
getOwnershipDescription(RD->getReferenceOwnership()));
2493+
}
2494+
// Diagnose generic signature change
2495+
if (getGenericSignature() != RD->getGenericSignature()) {
2496+
// Prefer sugared signature in diagnostics to be more user-friendly.
2497+
if (Ctx.commonVersionAtLeast(2) &&
2498+
getSugaredGenericSignature() != RD->getSugaredGenericSignature()) {
2499+
emitDiag(Loc, diag::generic_sig_change,
2500+
getSugaredGenericSignature(), RD->getSugaredGenericSignature());
2501+
} else {
2502+
emitDiag(Loc, diag::generic_sig_change,
2503+
getGenericSignature(), RD->getGenericSignature());
2504+
}
2505+
}
2506+
2507+
// ObjC name changes are considered breakage
2508+
if (getObjCName() != RD->getObjCName()) {
2509+
if (Ctx.commonVersionAtLeast(4)) {
2510+
emitDiag(Loc, diag::objc_name_change, getObjCName(), RD->getObjCName());
2511+
}
2512+
}
2513+
2514+
if (isOptional() != RD->isOptional()) {
2515+
if (Ctx.checkingABI()) {
2516+
// Both adding/removing optional is ABI-breaking.
2517+
emitDiag(Loc, diag::optional_req_changed, isOptional());
2518+
} else if (isOptional()) {
2519+
// Removing optional is source-breaking.
2520+
emitDiag(Loc, diag::optional_req_changed, isOptional());
2521+
}
2522+
}
2523+
2524+
// Diagnose removing attributes.
2525+
for (auto Kind: getDeclAttributes()) {
2526+
if (!RD->hasDeclAttribute(Kind)) {
2527+
if ((Ctx.checkingABI() ? DeclAttribute::isRemovingBreakingABI(Kind) :
2528+
DeclAttribute::isRemovingBreakingAPI(Kind)) &&
2529+
shouldDiagnoseRemovingAttribute(this, Kind)) {
2530+
emitDiag(Loc, diag::decl_new_attr,
2531+
Ctx.buffer((llvm::Twine("without ") + getAttrName(Kind)).str()));
2532+
}
2533+
}
2534+
}
2535+
2536+
// Diagnose adding attributes.
2537+
for (auto Kind: RD->getDeclAttributes()) {
2538+
if (!hasDeclAttribute(Kind)) {
2539+
if ((Ctx.checkingABI() ? DeclAttribute::isAddingBreakingABI(Kind) :
2540+
DeclAttribute::isAddingBreakingAPI(Kind)) &&
2541+
shouldDiagnoseAddingAttribute(this, Kind)) {
2542+
emitDiag(Loc, diag::decl_new_attr,
2543+
Ctx.buffer((llvm::Twine("with ") + getAttrName(Kind)).str()));
2544+
}
2545+
}
2546+
}
2547+
2548+
if (Ctx.checkingABI()) {
2549+
if (hasFixedBinaryOrder() && RD->hasFixedBinaryOrder() &&
2550+
getFixedBinaryOrder() != RD->getFixedBinaryOrder()) {
2551+
emitDiag(Loc, diag::decl_reorder, getFixedBinaryOrder(),
2552+
RD->getFixedBinaryOrder());
2553+
}
2554+
}
2555+
}
2556+
2557+
void swift::ide::api::SDKNodeDeclOperator::diagnose(SDKNode *Right) {
2558+
SDKNodeDecl::diagnose(Right);
2559+
auto *RO = dyn_cast<SDKNodeDeclOperator>(Right);
2560+
if (!RO)
2561+
return;
2562+
auto Loc = RO->getLoc();
2563+
if (getDeclKind() != RO->getDeclKind()) {
2564+
emitDiag(Loc, diag::decl_kind_changed, getDeclKindStr(RO->getDeclKind(),
2565+
getSDKContext().getOpts().CompilerStyle));
2566+
}
2567+
}
2568+
2569+
void swift::ide::api::SDKNodeDeclVar::diagnose(SDKNode *Right) {
2570+
SDKNodeDecl::diagnose(Right);
2571+
auto *RV = dyn_cast<SDKNodeDeclVar>(Right);
2572+
if (!RV)
2573+
return;
2574+
auto Loc = RV->getLoc();
2575+
if (Ctx.checkingABI()) {
2576+
if (hasFixedBinaryOrder() != RV->hasFixedBinaryOrder()) {
2577+
emitDiag(Loc, diag::var_has_fixed_order_change, hasFixedBinaryOrder());
2578+
}
2579+
}
2580+
}
2581+
2582+
static bool shouldDiagnoseType(SDKNodeType *T) {
2583+
return T->isTopLevelType();
2584+
}
2585+
2586+
void swift::ide::api::SDKNodeType::diagnose(SDKNode *Right) {
2587+
SDKNode::diagnose(Right);
2588+
auto *RT = dyn_cast<SDKNodeType>(Right);
2589+
if (!RT || !shouldDiagnoseType(this))
2590+
return;
2591+
assert(isTopLevelType());
2592+
2593+
// Diagnose type witness changes when diagnosing ABI breakages.
2594+
if (auto *Wit = dyn_cast<SDKNodeTypeWitness>(getParent())) {
2595+
auto *Conform = Wit->getParent()->getAs<SDKNodeConformance>();
2596+
if (Ctx.checkingABI() && getPrintedName() != RT->getPrintedName()) {
2597+
auto *LD = Conform->getNominalTypeDecl();
2598+
LD->emitDiag(SourceLoc(), diag::type_witness_change,
2599+
Wit->getWitnessedTypeName(),
2600+
getPrintedName(), RT->getPrintedName());
2601+
}
2602+
return;
2603+
}
2604+
2605+
StringRef Descriptor = getTypeRoleDescription();
2606+
assert(isa<SDKNodeDecl>(getParent()));
2607+
auto LParent = cast<SDKNodeDecl>(getParent());
2608+
assert(LParent->getKind() == RT->getParent()->getAs<SDKNodeDecl>()->getKind());
2609+
auto Loc = RT->getParent()->getAs<SDKNodeDecl>()->getLoc();
2610+
if (getPrintedName() != RT->getPrintedName()) {
2611+
LParent->emitDiag(Loc, diag::decl_type_change,
2612+
Descriptor, getPrintedName(), RT->getPrintedName());
2613+
}
2614+
2615+
if (hasDefaultArgument() && !RT->hasDefaultArgument()) {
2616+
LParent->emitDiag(Loc, diag::default_arg_removed, Descriptor);
2617+
}
2618+
if (getParamValueOwnership() != RT->getParamValueOwnership()) {
2619+
LParent->emitDiag(Loc, diag::param_ownership_change,
2620+
getTypeRoleDescription(),
2621+
getParamValueOwnership(),
2622+
RT->getParamValueOwnership());
2623+
}
2624+
}
2625+
2626+
void swift::ide::api::SDKNodeTypeFunc::diagnose(SDKNode *Right) {
2627+
SDKNodeType::diagnose(Right);
2628+
auto *RT = dyn_cast<SDKNodeTypeFunc>(Right);
2629+
if (!RT || !shouldDiagnoseType(this))
2630+
return;
2631+
assert(isTopLevelType());
2632+
auto Loc = RT->getParent()->getAs<SDKNodeDecl>()->getLoc();
2633+
if (Ctx.checkingABI() && isEscaping() != RT->isEscaping()) {
2634+
getParent()->getAs<SDKNodeDecl>()->emitDiag(Loc,
2635+
diag::func_type_escaping_changed,
2636+
getTypeRoleDescription(),
2637+
isEscaping());
2638+
}
2639+
}

0 commit comments

Comments
 (0)