[clang-tidy] Improve readability-enum-initial-value diagnostic message (#176485)
Enhance the readability-enum-initial-value checker to list which enumerators are not initialized in notes. This makes it easier for users to identify which specific enumerators need explicit initialization.
This commit is contained in:
parent
d12019d5e5
commit
d1e02cd31e
@ -165,22 +165,36 @@ void EnumInitialValueCheck::registerMatchers(MatchFinder *Finder) {
|
||||
|
||||
void EnumInitialValueCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
if (const auto *Enum = Result.Nodes.getNodeAs<EnumDecl>("inconsistent")) {
|
||||
const DiagnosticBuilder Diag =
|
||||
diag(
|
||||
Enum->getBeginLoc(),
|
||||
"initial values in enum '%0' are not consistent, consider explicit "
|
||||
"initialization of all, none or only the first enumerator")
|
||||
<< getName(Enum);
|
||||
for (const EnumConstantDecl *ECD : Enum->enumerators())
|
||||
if (ECD->getInitExpr() == nullptr) {
|
||||
const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
|
||||
ECD->getLocation(), 0, *Result.SourceManager, getLangOpts());
|
||||
if (EndLoc.isMacroID())
|
||||
continue;
|
||||
llvm::SmallString<8> Str{" = "};
|
||||
ECD->getInitVal().toString(Str);
|
||||
Diag << FixItHint::CreateInsertion(EndLoc, Str);
|
||||
// Emit warning first (DiagnosticBuilder emits on destruction), then notes.
|
||||
// Notes must follow the primary diagnostic or they may be dropped.
|
||||
{
|
||||
const DiagnosticBuilder Diag =
|
||||
diag(Enum->getBeginLoc(), "initial values in enum '%0' are not "
|
||||
"consistent, consider explicit "
|
||||
"initialization of all, none or only the "
|
||||
"first enumerator")
|
||||
<< getName(Enum);
|
||||
|
||||
for (const EnumConstantDecl *ECD : Enum->enumerators()) {
|
||||
if (ECD->getInitExpr() == nullptr) {
|
||||
const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
|
||||
ECD->getLocation(), 0, *Result.SourceManager, getLangOpts());
|
||||
if (EndLoc.isMacroID())
|
||||
continue;
|
||||
llvm::SmallString<8> Str{" = "};
|
||||
ECD->getInitVal().toString(Str);
|
||||
Diag << FixItHint::CreateInsertion(EndLoc, Str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const EnumConstantDecl *ECD : Enum->enumerators()) {
|
||||
if (ECD->getInitExpr() == nullptr) {
|
||||
diag(ECD->getLocation(), "uninitialized enumerator '%0' defined here",
|
||||
DiagnosticIDs::Note)
|
||||
<< ECD->getName();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -113,6 +113,11 @@ Changes in existing checks
|
||||
<clang-tidy/checks/performance/move-const-arg>` check by avoiding false
|
||||
positives on trivially copyable types with a non-public copy constructor.
|
||||
|
||||
- Improved :doc:`readability-enum-initial-value
|
||||
<clang-tidy/checks/readability/enum-initial-value>` check: the warning message
|
||||
now uses separate note diagnostics for each uninitialized enumerator, making
|
||||
it easier to see which specific enumerators need explicit initialization.
|
||||
|
||||
Removed checks
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@ -36,19 +36,25 @@ The following three cases are accepted:
|
||||
c2 = 2,
|
||||
};
|
||||
|
||||
enum D { // Invalid, d1 is not explicitly initialized!
|
||||
enum D { // warning: initial values in enum 'D' are not consistent,
|
||||
// consider explicit initialization of all, none or only
|
||||
// the first enumerator
|
||||
d0 = 0,
|
||||
d1,
|
||||
d1, // note: uninitialized enumerator 'd1' defined here
|
||||
d2 = 2,
|
||||
};
|
||||
|
||||
enum E { // Invalid, e1, e3, and e5 are not explicitly initialized.
|
||||
enum E { // warning: initial values in enum 'E' are not consistent,
|
||||
// consider explicit initialization of all, none or only
|
||||
// the first enumerator
|
||||
e0 = 0,
|
||||
e1,
|
||||
e1, // note: uninitialized enumerator 'e1' defined here
|
||||
e2 = 2,
|
||||
e3, // Dangerous, as the numeric values of e3 and e5 are both 3, and this is not explicitly visible in the code!
|
||||
e3, // note: uninitialized enumerator 'e3' defined here
|
||||
// Dangerous, as the numeric values of e3 and e5 are both 3,
|
||||
// and this is not explicitly visible in the code!
|
||||
e4 = 2,
|
||||
e5,
|
||||
e5, // note: uninitialized enumerator 'e5' defined here
|
||||
};
|
||||
|
||||
This check corresponds to the CERT C Coding Standard recommendation `INT09-C. Ensure enumeration constants map to unique values
|
||||
|
||||
@ -6,10 +6,12 @@
|
||||
// RUN: }}'
|
||||
|
||||
enum EError {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: initial values in enum 'EError' are not consistent
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: initial values in enum 'EError' are not consistent
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: initial values in enum 'EError' are not consistent, consider explicit initialization of all, none or only the first enumerator
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: initial values in enum 'EError' are not consistent, consider explicit initialization of all, none or only the first enumerator
|
||||
EError_a = 1,
|
||||
EError_b,
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: note: uninitialized enumerator 'EError_b' defined here
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:3: note: uninitialized enumerator 'EError_b' defined here
|
||||
// CHECK-FIXES: EError_b = 2,
|
||||
EError_c = 3,
|
||||
};
|
||||
@ -34,10 +36,14 @@ enum EAll {
|
||||
|
||||
#define ENUMERATOR_1 EMacro1_b
|
||||
enum EMacro1 {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: initial values in enum 'EMacro1' are not consistent
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: initial values in enum 'EMacro1' are not consistent
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: initial values in enum 'EMacro1' are not consistent, consider explicit initialization of all, none or only the first enumerator
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: initial values in enum 'EMacro1' are not consistent, consider explicit initialization of all, none or only the first enumerator
|
||||
EMacro1_a = 1,
|
||||
ENUMERATOR_1,
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: note: uninitialized enumerator 'EMacro1_b' defined here
|
||||
// CHECK-MESSAGES: note: expanded from macro 'ENUMERATOR_1'
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-3]]:3: note: uninitialized enumerator 'EMacro1_b' defined here
|
||||
// CHECK-MESSAGES-ENABLE: note: expanded from macro 'ENUMERATOR_1'
|
||||
// CHECK-FIXES: ENUMERATOR_1 = 2,
|
||||
EMacro1_c = 3,
|
||||
};
|
||||
@ -45,20 +51,24 @@ enum EMacro1 {
|
||||
|
||||
#define ENUMERATOR_2 EMacro2_b = 2
|
||||
enum EMacro2 {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: initial values in enum 'EMacro2' are not consistent
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: initial values in enum 'EMacro2' are not consistent
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: initial values in enum 'EMacro2' are not consistent, consider explicit initialization of all, none or only the first enumerator
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: initial values in enum 'EMacro2' are not consistent, consider explicit initialization of all, none or only the first enumerator
|
||||
EMacro2_a = 1,
|
||||
ENUMERATOR_2,
|
||||
EMacro2_c,
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: note: uninitialized enumerator 'EMacro2_c' defined here
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:3: note: uninitialized enumerator 'EMacro2_c' defined here
|
||||
// CHECK-FIXES: EMacro2_c = 3,
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: initial values in enum '<unnamed>' are not consistent
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: initial values in enum '<unnamed>' are not consistent
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: initial values in enum '<unnamed>' are not consistent, consider explicit initialization of all, none or only the first enumerator
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: initial values in enum '<unnamed>' are not consistent, consider explicit initialization of all, none or only the first enumerator
|
||||
EAnonymous_a = 1,
|
||||
EAnonymous_b,
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: note: uninitialized enumerator 'EAnonymous_b' defined here
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:3: note: uninitialized enumerator 'EAnonymous_b' defined here
|
||||
// CHECK-FIXES: EAnonymous_b = 2,
|
||||
EAnonymous_c = 3,
|
||||
};
|
||||
@ -94,12 +104,16 @@ enum EnumSequentialInitialValue {
|
||||
enum WithFwdDeclInconsistent : int;
|
||||
|
||||
enum WithFwdDeclInconsistent : int {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: initial values in enum 'WithFwdDeclInconsistent' are not consistent
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: initial values in enum 'WithFwdDeclInconsistent' are not consistent
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: initial values in enum 'WithFwdDeclInconsistent' are not consistent, consider explicit initialization of all, none or only the first enumerator
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: initial values in enum 'WithFwdDeclInconsistent' are not consistent, consider explicit initialization of all, none or only the first enumerator
|
||||
EFI0,
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: note: uninitialized enumerator 'EFI0' defined here
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:3: note: uninitialized enumerator 'EFI0' defined here
|
||||
// CHECK-FIXES: EFI0 = 0,
|
||||
EFI1 = 1,
|
||||
EFI2,
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: note: uninitialized enumerator 'EFI2' defined here
|
||||
// CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:3: note: uninitialized enumerator 'EFI2' defined here
|
||||
// CHECK-FIXES: EFI2 = 2,
|
||||
};
|
||||
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
// RUN: %check_clang_tidy %s readability-enum-initial-value %t
|
||||
|
||||
enum class EError {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: initial values in enum 'EError' are not consistent
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: initial values in enum 'EError' are not consistent, consider explicit initialization of all, none or only the first enumerator
|
||||
EError_a = 1,
|
||||
EError_b,
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: note: uninitialized enumerator 'EError_b' defined here
|
||||
// CHECK-FIXES: EError_b = 2,
|
||||
EError_c = 3,
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user