mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
swift-api-digester: teach the tool to directly compare two module interfaces
We used to use a Json format to capture the ABI/API detail of Swift modules to walk-around module compatibility issues across different compiler versions. Since Swift module now is in stable format, we can compare two swiftinterface files directly without dumping the content into Json format.
This commit is contained in:
@@ -98,6 +98,10 @@ static llvm::cl::list<std::string>
|
||||
FrameworkPaths("F", llvm::cl::desc("add a directory to the framework search path"),
|
||||
llvm::cl::cat(Category));
|
||||
|
||||
static llvm::cl::list<std::string>
|
||||
BaselineModuleInputPaths("BI", llvm::cl::desc("add a module for baseline input"),
|
||||
llvm::cl::cat(Category));
|
||||
|
||||
static llvm::cl::list<std::string>
|
||||
ModuleInputPaths("I", llvm::cl::desc("add a module for input"),
|
||||
llvm::cl::cat(Category));
|
||||
@@ -2074,6 +2078,33 @@ static void findTypeMemberDiffs(NodePtr leftSDKRoot, NodePtr rightSDKRoot,
|
||||
}
|
||||
}
|
||||
|
||||
static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule,
|
||||
SDKNodeRoot *RightModule, StringRef OutputPath,
|
||||
llvm::StringSet<> ProtocolReqWhitelist) {
|
||||
assert(LeftModule);
|
||||
assert(RightModule);
|
||||
llvm::raw_ostream *OS = &llvm::errs();
|
||||
std::unique_ptr<llvm::raw_ostream> FileOS;
|
||||
if (!OutputPath.empty()) {
|
||||
std::error_code EC;
|
||||
FileOS.reset(new llvm::raw_fd_ostream(OutputPath, EC, llvm::sys::fs::F_None));
|
||||
OS = FileOS.get();
|
||||
}
|
||||
ModuleDifferDiagsConsumer PDC(true, *OS);
|
||||
|
||||
Ctx.getDiags().addConsumer(PDC);
|
||||
TypeAliasDiffFinder(LeftModule, RightModule,
|
||||
Ctx.getTypeAliasUpdateMap()).search();
|
||||
PrunePass Prune(Ctx, std::move(ProtocolReqWhitelist));
|
||||
Prune.pass(LeftModule, RightModule);
|
||||
ChangeRefinementPass RefinementPass(Ctx.getNodeUpdateMap());
|
||||
RefinementPass.pass(LeftModule, RightModule);
|
||||
// Find member hoist changes to help refine diagnostics.
|
||||
findTypeMemberDiffs(LeftModule, RightModule, Ctx.getTypeMemberDiffs());
|
||||
DiagnosisEmitter::diagnosis(LeftModule, RightModule, Ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath,
|
||||
StringRef OutputPath,
|
||||
CheckerOptions Opts,
|
||||
@@ -2086,33 +2117,13 @@ static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath,
|
||||
llvm::errs() << RightPath << " does not exist\n";
|
||||
return 1;
|
||||
}
|
||||
llvm::raw_ostream *OS = &llvm::errs();
|
||||
std::unique_ptr<llvm::raw_ostream> FileOS;
|
||||
if (!OutputPath.empty()) {
|
||||
std::error_code EC;
|
||||
FileOS.reset(new llvm::raw_fd_ostream(OutputPath, EC, llvm::sys::fs::F_None));
|
||||
OS = FileOS.get();
|
||||
}
|
||||
ModuleDifferDiagsConsumer PDC(true, *OS);
|
||||
SDKContext Ctx(Opts);
|
||||
Ctx.getDiags().addConsumer(PDC);
|
||||
|
||||
SwiftDeclCollector LeftCollector(Ctx);
|
||||
LeftCollector.deSerialize(LeftPath);
|
||||
SwiftDeclCollector RightCollector(Ctx);
|
||||
RightCollector.deSerialize(RightPath);
|
||||
auto LeftModule = LeftCollector.getSDKRoot();
|
||||
auto RightModule = RightCollector.getSDKRoot();
|
||||
TypeAliasDiffFinder(LeftModule, RightModule,
|
||||
Ctx.getTypeAliasUpdateMap()).search();
|
||||
PrunePass Prune(Ctx, std::move(ProtocolReqWhitelist));
|
||||
Prune.pass(LeftModule, RightModule);
|
||||
ChangeRefinementPass RefinementPass(Ctx.getNodeUpdateMap());
|
||||
RefinementPass.pass(LeftModule, RightModule);
|
||||
// Find member hoist changes to help refine diagnostics.
|
||||
findTypeMemberDiffs(LeftModule, RightModule, Ctx.getTypeMemberDiffs());
|
||||
|
||||
DiagnosisEmitter::diagnosis(LeftModule, RightModule, Ctx);
|
||||
diagnoseModuleChange(Ctx, LeftCollector.getSDKRoot(), RightCollector.getSDKRoot(),
|
||||
OutputPath, std::move(ProtocolReqWhitelist));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2261,7 +2272,8 @@ void anchorForGetMainExecutable() {}
|
||||
|
||||
static int prepareForDump(const char *Main,
|
||||
CompilerInvocation &InitInvok,
|
||||
llvm::StringSet<> &Modules) {
|
||||
llvm::StringSet<> &Modules,
|
||||
bool IsBaseline = false) {
|
||||
InitInvok.setMainExecutablePath(fs::getMainExecutable(Main,
|
||||
reinterpret_cast<void *>(&anchorForGetMainExecutable)));
|
||||
InitInvok.setModuleName("swift_ide_test");
|
||||
@@ -2311,17 +2323,18 @@ static int prepareForDump(const char *Main,
|
||||
FramePaths.push_back({path, /*isSystem=*/true});
|
||||
}
|
||||
InitInvok.setFrameworkSearchPaths(FramePaths);
|
||||
InitInvok.setImportSearchPaths(options::ModuleInputPaths);
|
||||
|
||||
if (IsBaseline) {
|
||||
InitInvok.setImportSearchPaths(options::BaselineModuleInputPaths);
|
||||
} else {
|
||||
InitInvok.setImportSearchPaths(options::ModuleInputPaths);
|
||||
}
|
||||
if (!options::ModuleList.empty()) {
|
||||
if (readFileLineByLine(options::ModuleList, Modules))
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (auto M : options::ModuleNames) {
|
||||
Modules.insert(M);
|
||||
}
|
||||
|
||||
if (Modules.empty()) {
|
||||
llvm::errs() << "Need to specify -include-all or -module <name>\n";
|
||||
return 1;
|
||||
@@ -2384,6 +2397,15 @@ static CheckerOptions getCheckOpts() {
|
||||
return Opts;
|
||||
}
|
||||
|
||||
static SDKNodeRoot *getSDKRoot(const char *Main, SDKContext &Ctx,
|
||||
CheckerOptions Opts, bool IsBaseline) {
|
||||
CompilerInvocation Invok;
|
||||
llvm::StringSet<> Modules;
|
||||
if (prepareForDump(Main, Invok, Modules, IsBaseline))
|
||||
return nullptr;
|
||||
return getSDKNodeRoot(Ctx, Invok, Modules, Opts);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
PROGRAM_START(argc, argv);
|
||||
INITIALIZE_LLVM();
|
||||
@@ -2405,7 +2427,8 @@ int main(int argc, char *argv[]) {
|
||||
dumpSDKContent(InitInvok, Modules, options::OutputFile, Opts);
|
||||
case ActionType::MigratorGen:
|
||||
case ActionType::DiagnoseSDKs: {
|
||||
if (options::SDKJsonPaths.size() != 2) {
|
||||
bool CompareJson = options::SDKJsonPaths.size() == 2;
|
||||
if (!CompareJson && options::BaselineModuleInputPaths.empty()) {
|
||||
llvm::errs() << "Only two SDK versions can be compared\n";
|
||||
llvm::cl::PrintHelpMessage();
|
||||
return 1;
|
||||
@@ -2419,11 +2442,18 @@ int main(int argc, char *argv[]) {
|
||||
return generateMigrationScript(options::SDKJsonPaths[0],
|
||||
options::SDKJsonPaths[1],
|
||||
options::OutputFile, IgnoredUsrs, Opts);
|
||||
else
|
||||
else if (CompareJson)
|
||||
return diagnoseModuleChange(options::SDKJsonPaths[0],
|
||||
options::SDKJsonPaths[1],
|
||||
options::OutputFile, Opts,
|
||||
std::move(protocolWhitelist));
|
||||
else {
|
||||
SDKContext Ctx(Opts);
|
||||
return diagnoseModuleChange(Ctx, getSDKRoot(argv[0], Ctx, Opts, true),
|
||||
getSDKRoot(argv[0], Ctx, Opts, false),
|
||||
options::OutputFile,
|
||||
std::move(protocolWhitelist));
|
||||
}
|
||||
}
|
||||
case ActionType::DeserializeSDK:
|
||||
case ActionType::DeserializeDiffItems: {
|
||||
|
||||
Reference in New Issue
Block a user