Skip to content

Commit c8da38f

Browse files
authored
Merge pull request #20849 from akyrtzi/5.0-api-checker-protocol-whitelist
[5.0][api-digester] Add '-protocol-requirement-white-list' option to the digester for when diagnosing API breakage in SDKs
2 parents 797f61c + a10eed9 commit c8da38f

File tree

6 files changed

+85
-8
lines changed

6 files changed

+85
-8
lines changed

test/api-digester/Inputs/Foo-new-version/foo.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
-(void) someOptionalFunctionFromProt;
1010
@end
1111

12+
@protocol AnotherObjcProt
13+
-(void) anotherFunctionFromProt;
14+
-(void) anotherFunctionFromProt2;
15+
@end
16+
1217
@interface ClangInterface: NSObject <ObjcProt>
1318
- (void)someFunction;
1419
@end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
AnotherObjcProt

test/api-digester/Inputs/Foo/foo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
-(void) someFunctionFromProt;
55
@end
66

7+
@protocol AnotherObjcProt
8+
-(void) anotherFunctionFromProt;
9+
@end
10+
711
@interface ClangInterface: NSObject <ObjcProt>
812
- (void)someFunction;
913
@end

test/api-digester/Outputs/clang-module-dump.txt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,47 @@
33
"name": "TopLevel",
44
"printedName": "TopLevel",
55
"children": [
6+
{
7+
"kind": "TypeDecl",
8+
"name": "AnotherObjcProt",
9+
"printedName": "AnotherObjcProt",
10+
"children": [
11+
{
12+
"kind": "Function",
13+
"name": "anotherFunctionFromProt",
14+
"printedName": "anotherFunctionFromProt()",
15+
"children": [
16+
{
17+
"kind": "TypeNameAlias",
18+
"name": "Void",
19+
"printedName": "Void",
20+
"children": [
21+
{
22+
"kind": "TypeNominal",
23+
"name": "Void",
24+
"printedName": "()"
25+
}
26+
]
27+
}
28+
],
29+
"declKind": "Func",
30+
"usr": "c:objc(pl)AnotherObjcProt(im)anotherFunctionFromProt",
31+
"moduleName": "Foo",
32+
"genericSig": "<Self where Self : AnotherObjcProt>",
33+
"protocolReq": true,
34+
"declAttributes": [
35+
"ObjC"
36+
],
37+
"funcSelfKind": "NonMutating"
38+
}
39+
],
40+
"declKind": "Protocol",
41+
"usr": "c:objc(pl)AnotherObjcProt",
42+
"moduleName": "Foo",
43+
"declAttributes": [
44+
"ObjC"
45+
]
46+
},
647
{
748
"kind": "TypeDecl",
849
"name": "ClangInterface",

test/api-digester/compare-clang-dump.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %empty-directory(%t.module-cache)
22
// RUN: %api-digester -dump-sdk -module Foo -o %t.dump1.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %S/Inputs/Foo -avoid-location
33
// RUN: %api-digester -dump-sdk -module Foo -o %t.dump2.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %S/Inputs/Foo-new-version -avoid-location
4-
// RUN: %api-digester -diagnose-sdk -print-module --input-paths %t.dump1.json -input-paths %t.dump2.json -o %t.result
4+
// RUN: %api-digester -diagnose-sdk -protocol-requirement-white-list %S/Inputs/Foo-prot-whitelist.txt -print-module --input-paths %t.dump1.json -input-paths %t.dump2.json -o %t.result
55

66
// RUN: %clang -E -P -x c %S/Outputs/Foo-diff.txt -o - | sed '/^\s*$/d' > %t.expected
77
// RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.result.tmp

tools/swift-api-digester/swift-api-digester.cpp

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ static llvm::cl::opt<std::string>
6363
ModuleList("module-list-file",
6464
llvm::cl::desc("File containing a new-line separated list of modules"));
6565

66+
static llvm::cl::opt<std::string>
67+
ProtReqWhiteList("protocol-requirement-white-list",
68+
llvm::cl::desc("File containing a new-line separated list of protocol names"));
69+
6670
static llvm::cl::opt<std::string>
6771
OutputFile("o", llvm::cl::desc("Output file"));
6872

@@ -927,6 +931,7 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass {
927931

928932
SDKContext &Ctx;
929933
UpdatedNodesMap &UpdateMap;
934+
llvm::StringSet<> ProtocolReqWhitelist;
930935

931936
static void printSpaces(llvm::raw_ostream &OS, SDKNode *N) {
932937
assert(N);
@@ -959,6 +964,10 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass {
959964

960965
public:
961966
PrunePass(SDKContext &Ctx): Ctx(Ctx), UpdateMap(Ctx.getNodeUpdateMap()) {}
967+
PrunePass(SDKContext &Ctx, llvm::StringSet<> prWhitelist):
968+
Ctx(Ctx),
969+
UpdateMap(Ctx.getNodeUpdateMap()),
970+
ProtocolReqWhitelist(std::move(prWhitelist)) {}
962971

963972
void foundMatch(NodePtr Left, NodePtr Right, NodeMatchReason Reason) override {
964973
if (options::Verbose)
@@ -985,6 +994,12 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass {
985994
if (ATD->getDefault())
986995
ShouldComplain = false;
987996
}
997+
if (ShouldComplain &&
998+
ProtocolReqWhitelist.count(D->getParent()->getAs<SDKNodeDecl>()->getFullyQualifiedName())) {
999+
// Ignore protocol requirement additions if the protocol has been added
1000+
// to the whitelist.
1001+
ShouldComplain = false;
1002+
}
9881003
if (ShouldComplain)
9891004
Ctx.getDiags().diagnose(SourceLoc(), diag::protocol_req_added,
9901005
D->getScreenInfo());
@@ -2027,7 +2042,8 @@ static void findTypeMemberDiffs(NodePtr leftSDKRoot, NodePtr rightSDKRoot,
20272042

20282043
static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath,
20292044
StringRef OutputPath,
2030-
CheckerOptions Opts) {
2045+
CheckerOptions Opts,
2046+
llvm::StringSet<> ProtocolReqWhitelist) {
20312047
if (!fs::exists(LeftPath)) {
20322048
llvm::errs() << LeftPath << " does not exist\n";
20332049
return 1;
@@ -2055,7 +2071,7 @@ static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath,
20552071
auto RightModule = RightCollector.getSDKRoot();
20562072
TypeAliasDiffFinder(LeftModule, RightModule,
20572073
Ctx.getTypeAliasUpdateMap()).search();
2058-
PrunePass Prune(Ctx);
2074+
PrunePass Prune(Ctx, std::move(ProtocolReqWhitelist));
20592075
Prune.pass(LeftModule, RightModule);
20602076
ChangeRefinementPass RefinementPass(Ctx.getNodeUpdateMap());
20612077
RefinementPass.pass(LeftModule, RightModule);
@@ -2182,7 +2198,7 @@ static int compareSDKs(StringRef LeftPath, StringRef RightPath,
21822198
static int readFileLineByLine(StringRef Path, llvm::StringSet<> &Lines) {
21832199
auto FileBufOrErr = llvm::MemoryBuffer::getFile(Path);
21842200
if (!FileBufOrErr) {
2185-
llvm::errs() << "error opening file: "
2201+
llvm::errs() << "error opening file '" << Path << "': "
21862202
<< FileBufOrErr.getError().message() << '\n';
21872203
return 1;
21882204
}
@@ -2192,8 +2208,11 @@ static int readFileLineByLine(StringRef Path, llvm::StringSet<> &Lines) {
21922208
StringRef Line;
21932209
std::tie(Line, BufferText) = BufferText.split('\n');
21942210
Line = Line.trim();
2195-
if (!Line.empty())
2196-
Lines.insert(Line);
2211+
if (Line.empty())
2212+
continue;
2213+
if (Line.startswith("// ")) // comment.
2214+
continue;
2215+
Lines.insert(Line);
21972216
}
21982217
return 0;
21992218
}
@@ -2347,19 +2366,26 @@ int main(int argc, char *argv[]) {
23472366
return (prepareForDump(argv[0], InitInvok, Modules)) ? 1 :
23482367
dumpSDKContent(InitInvok, Modules, options::OutputFile, Opts);
23492368
case ActionType::CompareSDKs:
2350-
case ActionType::DiagnoseSDKs:
2369+
case ActionType::DiagnoseSDKs: {
23512370
if (options::SDKJsonPaths.size() != 2) {
23522371
llvm::errs() << "Only two SDK versions can be compared\n";
23532372
llvm::cl::PrintHelpMessage();
23542373
return 1;
23552374
}
2375+
llvm::StringSet<> protocolWhitelist;
2376+
if (!options::ProtReqWhiteList.empty()) {
2377+
if (readFileLineByLine(options::ProtReqWhiteList, protocolWhitelist))
2378+
return 1;
2379+
}
23562380
if (options::Action == ActionType::CompareSDKs)
23572381
return compareSDKs(options::SDKJsonPaths[0], options::SDKJsonPaths[1],
23582382
options::OutputFile, IgnoredUsrs, Opts);
23592383
else
23602384
return diagnoseModuleChange(options::SDKJsonPaths[0],
23612385
options::SDKJsonPaths[1],
2362-
options::OutputFile, Opts);
2386+
options::OutputFile, Opts,
2387+
std::move(protocolWhitelist));
2388+
}
23632389
case ActionType::DeserializeSDK:
23642390
case ActionType::DeserializeDiffItems: {
23652391
if (options::SDKJsonPaths.size() != 1) {

0 commit comments

Comments
 (0)