Skip to content

Commit 07fb294

Browse files
committed
[APIDigester] Provide a category when serializing diagnostics representing API or ABI breakage
1 parent 1263da1 commit 07fb294

File tree

8 files changed

+106
-45
lines changed

8 files changed

+106
-45
lines changed

include/swift/AST/DiagnosticConsumer.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct DiagnosticInfo {
4545
DiagnosticKind Kind;
4646
StringRef FormatString;
4747
ArrayRef<DiagnosticArgument> FormatArgs;
48+
StringRef Category;
4849

4950
/// Only used when directing diagnostics to different outputs.
5051
/// In batch mode a diagnostic may be
@@ -85,13 +86,13 @@ struct DiagnosticInfo {
8586

8687
DiagnosticInfo(DiagID ID, SourceLoc Loc, DiagnosticKind Kind,
8788
StringRef FormatString,
88-
ArrayRef<DiagnosticArgument> FormatArgs,
89+
ArrayRef<DiagnosticArgument> FormatArgs, StringRef Category,
8990
SourceLoc BufferIndirectlyCausingDiagnostic,
9091
ArrayRef<DiagnosticInfo *> ChildDiagnosticInfo,
9192
ArrayRef<CharSourceRange> Ranges, ArrayRef<FixIt> FixIts,
9293
bool IsChildNote)
9394
: ID(ID), Loc(Loc), Kind(Kind), FormatString(FormatString),
94-
FormatArgs(FormatArgs),
95+
FormatArgs(FormatArgs), Category(Category),
9596
BufferIndirectlyCausingDiagnostic(BufferIndirectlyCausingDiagnostic),
9697
ChildDiagnosticInfo(ChildDiagnosticInfo), Ranges(Ranges),
9798
FixIts(FixIts), IsChildNote(IsChildNote) {}

include/swift/AST/DiagnosticEngine.h

+4
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,10 @@ namespace swift {
10131013
/// option.
10141014
bool isDiagnosticPointsToFirstBadToken(DiagID id) const;
10151015

1016+
/// \returns true if the diagnostic is an API digester API or ABI breakage
1017+
/// diagnostic.
1018+
bool isAPIDigesterBreakageDiagnostic(DiagID id) const;
1019+
10161020
/// \returns true if any diagnostic consumer gave an error while invoking
10171021
//// \c finishProcessing.
10181022
bool finishProcessing();

include/swift/AST/DiagnosticsModuleDiffer.def

+34-34
Original file line numberDiff line numberDiff line change
@@ -20,73 +20,73 @@
2020
#define DEFINE_DIAGNOSTIC_MACROS
2121
#include "DefineDiagnosticMacros.h"
2222

23-
ERROR(generic_sig_change,none,"%0 has generic signature change from %1 to %2", (StringRef, StringRef, StringRef))
23+
ERROR(generic_sig_change,APIDigesterBreakage,"%0 has generic signature change from %1 to %2", (StringRef, StringRef, StringRef))
2424

25-
ERROR(raw_type_change,none,"%0(%1) is now %2 representable", (StringRef, StringRef, StringRef))
25+
ERROR(raw_type_change,APIDigesterBreakage,"%0(%1) is now %2 representable", (StringRef, StringRef, StringRef))
2626

27-
ERROR(removed_decl,none,"%0 has been removed%select{| (deprecated)}1", (StringRef, bool))
27+
ERROR(removed_decl,APIDigesterBreakage,"%0 has been removed%select{| (deprecated)}1", (StringRef, bool))
2828

29-
ERROR(moved_decl,none,"%0 has been moved to %1", (StringRef, StringRef))
29+
ERROR(moved_decl,APIDigesterBreakage,"%0 has been moved to %1", (StringRef, StringRef))
3030

31-
ERROR(renamed_decl,none,"%0 has been renamed to %1", (StringRef, StringRef))
31+
ERROR(renamed_decl,APIDigesterBreakage,"%0 has been renamed to %1", (StringRef, StringRef))
3232

33-
ERROR(decl_type_change,none,"%0 has %1 type change from %2 to %3", (StringRef, StringRef, StringRef, StringRef))
33+
ERROR(decl_type_change,APIDigesterBreakage,"%0 has %1 type change from %2 to %3", (StringRef, StringRef, StringRef, StringRef))
3434

35-
ERROR(decl_attr_change,none,"%0 changes from %1 to %2", (StringRef, StringRef, StringRef))
35+
ERROR(decl_attr_change,APIDigesterBreakage,"%0 changes from %1 to %2", (StringRef, StringRef, StringRef))
3636

37-
ERROR(decl_new_attr,none,"%0 is now %1", (StringRef, StringRef))
37+
ERROR(decl_new_attr,APIDigesterBreakage,"%0 is now %1", (StringRef, StringRef))
3838

39-
ERROR(decl_reorder,none,"%0 in a non-resilient type changes position from %1 to %2", (StringRef, unsigned, unsigned))
39+
ERROR(decl_reorder,APIDigesterBreakage,"%0 in a non-resilient type changes position from %1 to %2", (StringRef, unsigned, unsigned))
4040

41-
ERROR(decl_added,none,"%0 is added to a non-resilient type", (StringRef))
41+
ERROR(decl_added,APIDigesterBreakage,"%0 is added to a non-resilient type", (StringRef))
4242

43-
ERROR(var_has_fixed_order_change,none,"%0 is %select{now|no longer}1 a stored property", (StringRef, bool))
43+
ERROR(var_has_fixed_order_change,APIDigesterBreakage,"%0 is %select{now|no longer}1 a stored property", (StringRef, bool))
4444

45-
ERROR(func_has_fixed_order_change,none,"%0 is %select{now|no longer}1 a non-final instance function", (StringRef, bool))
45+
ERROR(func_has_fixed_order_change,APIDigesterBreakage,"%0 is %select{now|no longer}1 a non-final instance function", (StringRef, bool))
4646

47-
ERROR(default_arg_removed,none,"%0 has removed default argument from %1", (StringRef, StringRef))
47+
ERROR(default_arg_removed,APIDigesterBreakage,"%0 has removed default argument from %1", (StringRef, StringRef))
4848

49-
ERROR(conformance_removed,none,"%0 has removed %select{conformance to|inherited protocol}2 %1", (StringRef, StringRef, bool))
49+
ERROR(conformance_removed,APIDigesterBreakage,"%0 has removed %select{conformance to|inherited protocol}2 %1", (StringRef, StringRef, bool))
5050

51-
ERROR(conformance_added,none,"%0 has added inherited protocol %1", (StringRef, StringRef))
51+
ERROR(conformance_added,APIDigesterBreakage,"%0 has added inherited protocol %1", (StringRef, StringRef))
5252

53-
ERROR(existing_conformance_added,none,"%0 has added a conformance to an existing protocol %1", (StringRef, StringRef))
53+
ERROR(existing_conformance_added,APIDigesterBreakage,"%0 has added a conformance to an existing protocol %1", (StringRef, StringRef))
5454

55-
ERROR(default_associated_type_removed,none,"%0 has removed default type %1", (StringRef, StringRef))
55+
ERROR(default_associated_type_removed,APIDigesterBreakage,"%0 has removed default type %1", (StringRef, StringRef))
5656

57-
ERROR(protocol_req_added,none,"%0 has been added as a protocol requirement", (StringRef))
57+
ERROR(protocol_req_added,APIDigesterBreakage,"%0 has been added as a protocol requirement", (StringRef))
5858

59-
ERROR(super_class_removed,none,"%0 has removed its super class %1", (StringRef, StringRef))
59+
ERROR(super_class_removed,APIDigesterBreakage,"%0 has removed its super class %1", (StringRef, StringRef))
6060

61-
ERROR(super_class_changed,none,"%0 has changed its super class from %1 to %2", (StringRef, StringRef, StringRef))
61+
ERROR(super_class_changed,APIDigesterBreakage,"%0 has changed its super class from %1 to %2", (StringRef, StringRef, StringRef))
6262

63-
ERROR(decl_kind_changed,none,"%0 has been changed to a %1", (StringRef, StringRef))
63+
ERROR(decl_kind_changed,APIDigesterBreakage,"%0 has been changed to a %1", (StringRef, StringRef))
6464

65-
ERROR(optional_req_changed,none,"%0 is %select{now|no longer}1 an optional requirement", (StringRef, bool))
65+
ERROR(optional_req_changed,APIDigesterBreakage,"%0 is %select{now|no longer}1 an optional requirement", (StringRef, bool))
6666

67-
ERROR(no_longer_open,none,"%0 is no longer open for subclassing", (StringRef))
67+
ERROR(no_longer_open,APIDigesterBreakage,"%0 is no longer open for subclassing", (StringRef))
6868

69-
ERROR(func_type_escaping_changed,none,"%0 has %select{removed|added}2 @escaping in %1", (StringRef, StringRef, bool))
69+
ERROR(func_type_escaping_changed,APIDigesterBreakage,"%0 has %select{removed|added}2 @escaping in %1", (StringRef, StringRef, bool))
7070

71-
ERROR(func_self_access_change,none,"%0 has self access kind changing from %1 to %2", (StringRef, StringRef, StringRef))
71+
ERROR(func_self_access_change,APIDigesterBreakage,"%0 has self access kind changing from %1 to %2", (StringRef, StringRef, StringRef))
7272

73-
ERROR(param_ownership_change,none,"%0 has %1 changing from %2 to %3", (StringRef, StringRef, StringRef, StringRef))
73+
ERROR(param_ownership_change,APIDigesterBreakage,"%0 has %1 changing from %2 to %3", (StringRef, StringRef, StringRef, StringRef))
7474

75-
ERROR(type_witness_change,none,"%0 has type witness type for %1 changing from %2 to %3", (StringRef, StringRef, StringRef, StringRef))
75+
ERROR(type_witness_change,APIDigesterBreakage,"%0 has type witness type for %1 changing from %2 to %3", (StringRef, StringRef, StringRef, StringRef))
7676

77-
ERROR(decl_new_witness_table_entry,none,"%0 now requires%select{| no}1 new witness table entry", (StringRef, bool))
77+
ERROR(decl_new_witness_table_entry,APIDigesterBreakage,"%0 now requires%select{| no}1 new witness table entry", (StringRef, bool))
7878

79-
ERROR(new_decl_without_intro,none,"%0 is a new API without @available attribute", (StringRef))
79+
ERROR(new_decl_without_intro,APIDigesterBreakage,"%0 is a new API without @available attribute", (StringRef))
8080

81-
ERROR(objc_name_change,none,"%0 has ObjC name change from %1 to %2", (StringRef, StringRef, StringRef))
81+
ERROR(objc_name_change,APIDigesterBreakage,"%0 has ObjC name change from %1 to %2", (StringRef, StringRef, StringRef))
8282

83-
ERROR(desig_init_added,none,"%0 has been added as a designated initializer to an open class", (StringRef))
83+
ERROR(desig_init_added,APIDigesterBreakage,"%0 has been added as a designated initializer to an open class", (StringRef))
8484

85-
ERROR(added_invisible_designated_init,none,"%0 has new designated initializers that are not visible to clients", (StringRef))
85+
ERROR(added_invisible_designated_init,APIDigesterBreakage,"%0 has new designated initializers that are not visible to clients", (StringRef))
8686

87-
ERROR(not_inheriting_convenience_inits,none,"%0 no longer inherits convenience inits from its superclass", (StringRef))
87+
ERROR(not_inheriting_convenience_inits,APIDigesterBreakage,"%0 no longer inherits convenience inits from its superclass", (StringRef))
8888

89-
ERROR(enum_case_added,none,"%0 has been added as a new enum case", (StringRef))
89+
ERROR(enum_case_added,APIDigesterBreakage,"%0 has been added as a new enum case", (StringRef))
9090

9191
WARNING(cannot_read_allowlist,none,"cannot read breakage allowlist at '%0'", (StringRef))
9292

lib/AST/DiagnosticEngine.cpp

+21-5
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,25 @@ enum class DiagnosticOptions {
5252

5353
/// After a fatal error subsequent diagnostics are suppressed.
5454
Fatal,
55+
56+
/// An API or ABI breakage diagnostic emitted by the API digester.
57+
APIDigesterBreakage,
5558
};
5659
struct StoredDiagnosticInfo {
5760
DiagnosticKind kind : 2;
5861
bool pointsToFirstBadToken : 1;
5962
bool isFatal : 1;
63+
bool isAPIDigesterBreakage : 1;
6064

6165
constexpr StoredDiagnosticInfo(DiagnosticKind k, bool firstBadToken,
62-
bool fatal)
63-
: kind(k), pointsToFirstBadToken(firstBadToken), isFatal(fatal) {}
66+
bool fatal, bool isAPIDigesterBreakage)
67+
: kind(k), pointsToFirstBadToken(firstBadToken), isFatal(fatal),
68+
isAPIDigesterBreakage(isAPIDigesterBreakage) {}
6469
constexpr StoredDiagnosticInfo(DiagnosticKind k, DiagnosticOptions opts)
6570
: StoredDiagnosticInfo(k,
6671
opts == DiagnosticOptions::PointsToFirstBadToken,
67-
opts == DiagnosticOptions::Fatal) {}
72+
opts == DiagnosticOptions::Fatal,
73+
opts == DiagnosticOptions::APIDigesterBreakage) {}
6874
};
6975

7076
// Reproduce the DiagIDs, as we want both the size and access to the raw ids
@@ -316,6 +322,10 @@ bool DiagnosticEngine::isDiagnosticPointsToFirstBadToken(DiagID ID) const {
316322
return storedDiagnosticInfos[(unsigned) ID].pointsToFirstBadToken;
317323
}
318324

325+
bool DiagnosticEngine::isAPIDigesterBreakageDiagnostic(DiagID ID) const {
326+
return storedDiagnosticInfos[(unsigned)ID].isAPIDigesterBreakage;
327+
}
328+
319329
bool DiagnosticEngine::finishProcessing() {
320330
bool hadError = false;
321331
for (auto &Consumer : Consumers) {
@@ -1092,11 +1102,17 @@ DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic) {
10921102
}
10931103
}
10941104

1105+
// Currently, only API digester diagnostics are assigned a category.
1106+
StringRef Category;
1107+
if (isAPIDigesterBreakageDiagnostic(diagnostic.getID()))
1108+
Category = "api-digester-breaking-change";
1109+
10951110
return DiagnosticInfo(
10961111
diagnostic.getID(), loc, toDiagnosticKind(behavior),
10971112
diagnosticStringFor(diagnostic.getID(), getPrintDiagnosticNames()),
1098-
diagnostic.getArgs(), getDefaultDiagnosticLoc(), /*child note info*/ {},
1099-
diagnostic.getRanges(), diagnostic.getFixIts(), diagnostic.isChildNote());
1113+
diagnostic.getArgs(), Category, getDefaultDiagnosticLoc(),
1114+
/*child note info*/ {}, diagnostic.getRanges(), diagnostic.getFixIts(),
1115+
diagnostic.isChildNote());
11001116
}
11011117

11021118
void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) {

lib/Frontend/SerializedDiagnosticConsumer.cpp

+30-2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ struct SharedState : llvm::RefCountedBase<SharedState> {
8484
/// The collection of files used.
8585
llvm::DenseMap<const char *, unsigned> Files;
8686

87+
/// The collection of categories used.
88+
llvm::DenseMap<const char *, unsigned> Categories;
89+
8790
using DiagFlagsTy =
8891
llvm::DenseMap<const void *, std::pair<unsigned, StringRef>>;
8992

@@ -187,6 +190,9 @@ class SerializedDiagnosticConsumer : public DiagnosticConsumer {
187190
// Record identifier for the file.
188191
unsigned getEmitFile(StringRef Filename);
189192

193+
// Record identifier for the category.
194+
unsigned getEmitCategory(StringRef Category);
195+
190196
/// Add a source location to a record.
191197
void addLocToRecord(SourceLoc Loc,
192198
SourceManager &SM,
@@ -235,6 +241,23 @@ unsigned SerializedDiagnosticConsumer::getEmitFile(StringRef Filename) {
235241
return entry;
236242
}
237243

244+
unsigned SerializedDiagnosticConsumer::getEmitCategory(StringRef Category) {
245+
unsigned &entry = State->Categories[Category.data()];
246+
if (entry)
247+
return entry;
248+
249+
// Lazily generate the record for the category.
250+
entry = State->Categories.size();
251+
RecordData Record;
252+
Record.push_back(RECORD_CATEGORY);
253+
Record.push_back(entry);
254+
Record.push_back(Category.size());
255+
State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_CATEGORY), Record,
256+
Category.data());
257+
258+
return entry;
259+
}
260+
238261
void SerializedDiagnosticConsumer::addLocToRecord(SourceLoc Loc,
239262
SourceManager &SM,
240263
StringRef Filename,
@@ -469,8 +492,13 @@ emitDiagnosticMessage(SourceManager &SM,
469492
Record.push_back(getDiagnosticLevel(Kind));
470493
addLocToRecord(Loc, SM, filename, Record);
471494

472-
// FIXME: Swift diagnostics currently have no category.
473-
Record.push_back(0);
495+
// Emit the category.
496+
if (!Info.Category.empty()) {
497+
Record.push_back(getEmitCategory(Info.Category));
498+
} else {
499+
Record.push_back(0);
500+
}
501+
474502
// FIXME: Swift diagnostics currently have no flags.
475503
Record.push_back(0);
476504

lib/FrontendTool/FrontendTool.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -1973,9 +1973,10 @@ int swift::performFrontend(ArrayRef<const char *> Args,
19731973
DiagnosticInfo errorInfo(
19741974
DiagID(0), SourceLoc(), DiagnosticKind::Error,
19751975
"fatal error encountered during compilation; " SWIFT_BUG_REPORT_MESSAGE,
1976-
{}, SourceLoc(), {}, {}, {}, false);
1976+
{}, StringRef(), SourceLoc(), {}, {}, {}, false);
19771977
DiagnosticInfo noteInfo(DiagID(0), SourceLoc(), DiagnosticKind::Note,
1978-
reason, {}, SourceLoc(), {}, {}, {}, false);
1978+
reason, {}, StringRef(), SourceLoc(), {}, {}, {},
1979+
false);
19791980
PDC.handleDiagnostic(dummyMgr, errorInfo);
19801981
PDC.handleDiagnostic(dummyMgr, noteInfo);
19811982
if (shouldCrash)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// REQUIRES: VENDOR=apple
2+
3+
// RUN: %empty-directory(%t)
4+
5+
// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -emit-module -o %t/color.swiftmodule %S/Inputs/cake_baseline/color.swift -parse-as-library -enable-library-evolution %clang-importer-sdk-nosource -module-name color
6+
// RUN: not %api-digester -diagnose-sdk -serialize-diagnostics-path %t/result.dia -empty-baseline -I %t %clang-importer-sdk-nosource -module color -abi
7+
// RUN: c-index-test -read-diagnostics %t/result.dia 2>&1 | %FileCheck %s -check-prefix CHECK-DIA
8+
9+
// Ensure the 'api-digester-breaking-change' category is included in the serialized diagnostics file.
10+
// CHECK-DIA: error: ABI breakage: enum Color is a new API without @available attribute [] [api-digester-breaking-change]

unittests/AST/DiagnosticConsumerTests.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ namespace {
5454
DiagnosticInfo testDiagnosticInfo(SourceLoc Loc, const char *Message,
5555
DiagnosticKind Kind) {
5656
return DiagnosticInfo(DiagID(0), Loc, Kind, Message, /*args*/ {},
57+
/*category*/ StringRef(),
5758
/*indirectBuffer*/ SourceLoc(), /*childInfo*/ {},
5859
/*ranges*/ {}, /*fixIts*/ {}, /*isChild*/ false);
5960
}

0 commit comments

Comments
 (0)