Skip to content

Commit f23857c

Browse files
committed
[clang] [diagnostics] Stable IDs for Clang diagnostics
SARIF diagnostics require that each rule have a stable `id` property to identify that rule across runs, even when the compiler or analysis tool has changed. We were previously setting the `id` property to the numeric value of the enum value for that diagnostic within the Clang implementation; this value changes whenever an unrelated diagnostic is inserted or removed earlier in the list. This change sets the `id` property to the _text_ of that same enum value. This value would only change if someone renames the enum value for that diagnostic, which should happen much less frequently than renumbering. For now, we will just assume that renaming happens infrequently enough that existing consumers of SARIF will not notice. In the future, we could take advantage of SARIF's support for `deprecatedIds`, which let a rule specify the IDs by which it was previously known. This would let us rename, split, or combine diagnostics while still being able to correlate the new diagnostic IDs with older SARIF logs and/or suppressions. Nothing in this change affects how warnings are configured on the command line or in `#pragma clang diagnostic`. Those still use warning groups, not the stable IDs.
1 parent 1429628 commit f23857c

File tree

4 files changed

+68
-20
lines changed

4 files changed

+68
-20
lines changed

clang/include/clang/Basic/DiagnosticIDs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,9 @@ class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
332332
/// Given a diagnostic ID, return a description of the issue.
333333
StringRef getDescription(unsigned DiagID) const;
334334

335+
/// Given a diagnostic ID, return the stable ID of the diagnostic.
336+
std::string getStableID(unsigned DiagID) const;
337+
335338
/// Return true if the unmapped diagnostic levelof the specified
336339
/// diagnostic ID is a Warning or Extension.
337340
///

clang/lib/Basic/DiagnosticIDs.cpp

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,22 @@ const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = {
5151
#undef DIAG
5252
};
5353

54+
struct StaticDiagInfoStableIDStringTable {
55+
#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
56+
SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
57+
char ENUM##_id[sizeof(#ENUM)];
58+
#include "clang/Basic/AllDiagnosticKinds.inc"
59+
#undef DIAG
60+
};
61+
62+
const StaticDiagInfoStableIDStringTable StaticDiagInfoStableIDs = {
63+
#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
64+
SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
65+
#ENUM,
66+
#include "clang/Basic/AllDiagnosticKinds.inc"
67+
#undef DIAG
68+
};
69+
5470
extern const StaticDiagInfoRec StaticDiagInfo[];
5571

5672
// Stored separately from StaticDiagInfoRec to pack better. Otherwise,
@@ -63,6 +79,14 @@ const uint32_t StaticDiagInfoDescriptionOffsets[] = {
6379
#undef DIAG
6480
};
6581

82+
const uint32_t StaticDiagInfoStableIDOffsets[] = {
83+
#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
84+
SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
85+
offsetof(StaticDiagInfoStableIDStringTable, ENUM##_id),
86+
#include "clang/Basic/AllDiagnosticKinds.inc"
87+
#undef DIAG
88+
};
89+
6690
enum DiagnosticClass {
6791
CLASS_NOTE = DiagnosticIDs::CLASS_NOTE,
6892
CLASS_REMARK = DiagnosticIDs::CLASS_REMARK,
@@ -95,6 +119,7 @@ struct StaticDiagInfoRec {
95119
uint16_t Deferrable : 1;
96120

97121
uint16_t DescriptionLen;
122+
uint16_t StableIDLen;
98123

99124
unsigned getOptionGroupIndex() const {
100125
return OptionGroupIndex;
@@ -107,6 +132,14 @@ struct StaticDiagInfoRec {
107132
return StringRef(&Table[StringOffset], DescriptionLen);
108133
}
109134

135+
StringRef getStableID() const {
136+
size_t MyIndex = this - &StaticDiagInfo[0];
137+
uint32_t StringOffset = StaticDiagInfoStableIDOffsets[MyIndex];
138+
const char *Table =
139+
reinterpret_cast<const char *>(&StaticDiagInfoStableIDs);
140+
return StringRef(&Table[StringOffset], StableIDLen);
141+
}
142+
110143
diag::Flavor getFlavor() const {
111144
return Class == CLASS_REMARK ? diag::Flavor::Remark
112145
: diag::Flavor::WarningOrError;
@@ -159,7 +192,8 @@ const StaticDiagInfoRec StaticDiagInfo[] = {
159192
SHOWINSYSMACRO, \
160193
GROUP, \
161194
DEFERRABLE, \
162-
STR_SIZE(DESC, uint16_t)},
195+
STR_SIZE(DESC, uint16_t), \
196+
STR_SIZE(#ENUM, uint16_t)},
163197
#include "clang/Basic/DiagnosticCommonKinds.inc"
164198
#include "clang/Basic/DiagnosticDriverKinds.inc"
165199
#include "clang/Basic/DiagnosticFrontendKinds.inc"
@@ -434,6 +468,15 @@ StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
434468
return CustomDiagInfo->getDescription(DiagID).GetDescription();
435469
}
436470

471+
/// getIDString - Given a diagnostic ID, return the stable ID of the diagnostic.
472+
std::string DiagnosticIDs::getStableID(unsigned DiagID) const {
473+
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
474+
return Info->getStableID().str();
475+
assert(CustomDiagInfo && "Invalid CustomDiagInfo");
476+
// TODO: Stable IDs for custom diagnostics?
477+
return std::to_string(DiagID);
478+
}
479+
437480
static DiagnosticIDs::Level toLevel(diag::Severity SV) {
438481
switch (SV) {
439482
case diag::Severity::Ignored:

clang/lib/Frontend/SARIFDiagnostic.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ void SARIFDiagnostic::emitDiagnosticMessage(
4646
if (!Diag)
4747
return;
4848

49-
SarifRule Rule = SarifRule::create().setRuleId(std::to_string(Diag->getID()));
49+
std::string StableID =
50+
Diag->getDiags()->getDiagnosticIDs()->getStableID(Diag->getID());
51+
SarifRule Rule = SarifRule::create().setRuleId(StableID);
5052

5153
Rule = addDiagnosticLevelToRule(Rule, Level);
5254

clang/test/Frontend/sarif-diagnostics.cpp

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,35 +34,35 @@ void f1(t1 x, t1 y) {
3434
// Omit filepath to llvm project directory
3535
// CHECK: test/Frontend/sarif-diagnostics.cpp"},"mimeType":"text/plain","roles":["resultFile"]}],"columnKind":"unicodeCodePoints","results":
3636
// CHECK: [{"level":"error","locations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file://
37-
// CHECK: {"endColumn":1,"startColumn":1,"startLine":12}}}],"message":{"text":"'main' must return 'int'"},"ruleId":"{{[0-9]+}}","ruleIndex":0},
37+
// CHECK: {"endColumn":1,"startColumn":1,"startLine":12}}}],"message":{"text":"'main' must return 'int'"},"ruleId":"{{[A-Za-z0-9_]+}}","ruleIndex":0},
3838
// CHECK: {"level":"error","locations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file://
3939
// CHECK: {"endColumn":11,"startColumn":11,"startLine":13}}}],"message":{"text":"use of undeclared identifier
40-
// CHECK: 'hello'"},"ruleId":"{{[0-9]+}}","ruleIndex":1},{"level":"error","locations":[{"physicalLocation":{"artifactLocation":
40+
// CHECK: 'hello'"},"ruleId":"{{[A-Za-z0-9_]+}}","ruleIndex":1},{"level":"error","locations":[{"physicalLocation":{"artifactLocation":
4141
// CHECK: {"index":0,"uri":"file://{{.+}}"},"region":{"endColumn":17,"startColumn":17,"startLine":15}}}],"message":{"text":"invalid digit 'a' in decimal
42-
// CHECK: constant"},"ruleId":"{{[0-9]+}}","ruleIndex":2},{"level":"warning","locations":[{"physicalLocation":{"artifactLocation":
42+
// CHECK: constant"},"ruleId":"{{[A-Za-z0-9_]+}}","ruleIndex":2},{"level":"warning","locations":[{"physicalLocation":{"artifactLocation":
4343
// CHECK: {"index":0,"uri":"file://{{.+}}"},"region":{"endColumn":5,"startColumn":5,"startLine":19}}}],"message":{"text":"misleading indentation; statement is not part
44-
// CHECK: of the previous 'if'"},"ruleId":"{{[0-9]+}}","ruleIndex":3},{"level":"note","locations":[{"physicalLocation":{"artifactLocation":
44+
// CHECK: of the previous 'if'"},"ruleId":"{{[A-Za-z0-9_]+}}","ruleIndex":3},{"level":"note","locations":[{"physicalLocation":{"artifactLocation":
4545
// CHECK: {"index":0,"uri":"file://{{.+}}"},"region":{"endColumn":3,"startColumn":3,"startLine":17}}}],"message":{"text":"previous statement is
46-
// CHECK: here"},"ruleId":"{{[0-9]+}}","ruleIndex":4},{"level":"warning","locations":[{"physicalLocation":{"artifactLocation":
46+
// CHECK: here"},"ruleId":"{{[A-Za-z0-9_]+}}","ruleIndex":4},{"level":"warning","locations":[{"physicalLocation":{"artifactLocation":
4747
// CHECK: {"index":0,"uri":"file://{{.+}}"},"region":{"endColumn":10,"startColumn":10,"startLine":18}}}],"message":{"text":"unused variable
48-
// CHECK: 'Yes'"},"ruleId":"{{[0-9]+}}","ruleIndex":5},{"level":"error","locations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file://
48+
// CHECK: 'Yes'"},"ruleId":"{{[A-Za-z0-9_]+}}","ruleIndex":5},{"level":"error","locations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file://
4949
// CHECK: {"endColumn":12,"startColumn":12,"startLine":21}}}],"message":{"text":"use of undeclared identifier
50-
// CHECK: 'hi'"},"ruleId":"{{[0-9]+}}","ruleIndex":6},{"level":"error","locations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file://
50+
// CHECK: 'hi'"},"ruleId":"{{[A-Za-z0-9_]+}}","ruleIndex":6},{"level":"error","locations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file://
5151
// CHECK: {"endColumn":1,"startColumn":1,"startLine":23}}}],"message":{"text":"extraneous closing brace
52-
// CHECK: ('}')"},"ruleId":"{{[0-9]+}}","ruleIndex":7},{"level":"error","locations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file://
52+
// CHECK: ('}')"},"ruleId":"{{[A-Za-z0-9_]+}}","ruleIndex":7},{"level":"error","locations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file://
5353
// CHECK: {"endColumn":6,"endLine":27,"startColumn":5,"startLine":27}}},{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file://
5454
// CHECK: {"endColumn":10,"endLine":27,"startColumn":9,"startLine":27}}},{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file://
5555
// CHECK: {"endColumn":7,"startColumn":7,"startLine":27}}}],"message":{"text":"invalid operands to binary expression ('t1' and
56-
// CHECK: 't1')"},"ruleId":"{{[0-9]+}}","ruleIndex":8}],"tool":{"driver":{"fullName":"","informationUri":"https://clang.llvm.org/docs/
56+
// CHECK: 't1')"},"ruleId":"{{[A-Za-z0-9_]+}}","ruleIndex":8}],"tool":{"driver":{"fullName":"","informationUri":"https://clang.llvm.org/docs/
5757
// CHECK: UsersManual.html","language":"en-US","name":"clang","rules":[{"defaultConfiguration":
58-
// CHECK: {"enabled":true,"level":"error","rank":50},"fullDescription":{"text":""},"id":"{{[0-9]+}}","name":""},{"defaultConfiguration":
59-
// CHECK: {"enabled":true,"level":"error","rank":50},"fullDescription":{"text":""},"id":"{{[0-9]+}}","name":""},{"defaultConfiguration":
60-
// CHECK: {"enabled":true,"level":"error","rank":50},"fullDescription":{"text":""},"id":"{{[0-9]+}}","name":""},{"defaultConfiguration":
61-
// CHECK: {"enabled":true,"level":"warning","rank":-1},"fullDescription":{"text":""},"id":"{{[0-9]+}}","name":""},{"defaultConfiguration":
62-
// CHECK: {"enabled":true,"level":"note","rank":-1},"fullDescription":{"text":""},"id":"{{[0-9]+}}","name":""},{"defaultConfiguration":
63-
// CHECK: {"enabled":true,"level":"warning","rank":-1},"fullDescription":{"text":""},"id":"{{[0-9]+}}","name":""},{"defaultConfiguration":
64-
// CHECK: {"enabled":true,"level":"error","rank":50},"fullDescription":{"text":""},"id":"{{[0-9]+}}","name":""},{"defaultConfiguration":
65-
// CHECK: {"enabled":true,"level":"error","rank":50},"fullDescription":{"text":""},"id":"{{[0-9]+}}","name":""},{"defaultConfiguration":
58+
// CHECK: {"enabled":true,"level":"error","rank":50},"fullDescription":{"text":""},"id":"{{[A-Za-z0-9_]+}}","name":""},{"defaultConfiguration":
59+
// CHECK: {"enabled":true,"level":"error","rank":50},"fullDescription":{"text":""},"id":"{{[A-Za-z0-9_]+}}","name":""},{"defaultConfiguration":
60+
// CHECK: {"enabled":true,"level":"error","rank":50},"fullDescription":{"text":""},"id":"{{[A-Za-z0-9_]+}}","name":""},{"defaultConfiguration":
61+
// CHECK: {"enabled":true,"level":"warning","rank":-1},"fullDescription":{"text":""},"id":"{{[A-Za-z0-9_]+}}","name":""},{"defaultConfiguration":
62+
// CHECK: {"enabled":true,"level":"note","rank":-1},"fullDescription":{"text":""},"id":"{{[A-Za-z0-9_]+}}","name":""},{"defaultConfiguration":
63+
// CHECK: {"enabled":true,"level":"warning","rank":-1},"fullDescription":{"text":""},"id":"{{[A-Za-z0-9_]+}}","name":""},{"defaultConfiguration":
64+
// CHECK: {"enabled":true,"level":"error","rank":50},"fullDescription":{"text":""},"id":"{{[A-Za-z0-9_]+}}","name":""},{"defaultConfiguration":
65+
// CHECK: {"enabled":true,"level":"error","rank":50},"fullDescription":{"text":""},"id":"{{[A-Za-z0-9_]+}}","name":""},{"defaultConfiguration":
6666
// CHECK: {"enabled":true,"level":"error","rank":50},"fullDescription":
67-
// CHECK: {"text":""},"id":"{{[0-9]+}}","name":""}],"version":"{{[0-9]+\.[0-9]+\.[0-9]+[^" ]*}}"}}}],"version":"2.1.0"}
67+
// CHECK: {"text":""},"id":"{{[A-Za-z0-9_]+}}","name":""}],"version":"{{[0-9]+\.[0-9]+\.[0-9]+[^" ]*}}"}}}],"version":"2.1.0"}
6868
// CHECK: 2 warnings and 6 errors generated.

0 commit comments

Comments
 (0)