bugprone-tagged-union-member-count

针对标记联合体发出警告,其中标记的数量与联合体内的成员数据数量不同。

如果一个结构体或类正好包含一个联合体成员数据和一个枚举成员数据,以及任意数量的既不是联合体也不是枚举的其他成员数据,则它被认为是一个标记联合体。

示例

enum Tags {
  Tag1,
  Tag2,
};

struct TaggedUnion { // warning: tagged union has more data members (3) than tags (2)
  enum Tags Kind;
  union {
    int I;
    float F;
    char *Str;
  } Data;
};

如何计算枚举常量

在计算枚举常量数量时,最复杂的一点是其中一些常量可能是辅助值,它们有意没有对应的联合体成员数据,并且用于其他目的。例如,最后一个枚举常量有时明确地“指向”最后一个声明的有效枚举常量,或者跟踪已声明的枚举常量的数量。

为了说明

enum TagWithLast {
  Tag1 = 0,
  Tag2 = 1,
  Tag3 = 2,
  LastTag = 2
};

enum TagWithCounter {
  Tag1, // is 0
  Tag2, // is 1
  Tag3, // is 2
  TagCount, // is 3
};

该检查会计算枚举常量中不同值的数量,而不是枚举常量本身。这样,本质上只是其他枚举常量别名的枚举常量就不会包含在最终计数中。

枚举常量计数的处理(如之前代码示例中的 TagCount)是通过在最后一个枚举常量的名称以 CountingEnumPrefixesCountingEnumSuffixes 中指定的某个前缀开头或以某个后缀结尾,并且其值为枚举中不同值的总数减 1 时,将枚举值的数量减 1 来完成的。

当最终计数根据此启发式方法进行调整时,将发出一个诊断提示,显示哪个枚举常量匹配了该条件。

可以完全禁用此启发式方法 (EnableCountingEnumHeuristic),或者配置为遵循你的命名约定 (CountingEnumPrefixesCountingEnumSuffixes)。在 CountingEnumPrefixesCountingEnumSuffixes 中指定的字符串不区分大小写匹配。

示例计数

// Enum count is 3, because the value 2 is counted only once
enum TagWithLast {
  Tag1 = 0,
  Tag2 = 1,
  Tag3 = 2,
  LastTag = 2
};

// Enum count is 3, because TagCount is heuristically excluded
enum TagWithCounter {
  Tag1, // is 0
  Tag2, // is 1
  Tag3, // is 2
  TagCount, // is 3
};

选项

EnableCountingEnumHeuristic

此选项启用或禁用枚举计数启发式方法。它使用选项 CountingEnumPrefixesCountingEnumSuffixes 中指定的词缀和后缀,通过使用它们进行词缀和后缀匹配来查找枚举计数常量。

此选项默认启用。

EnableCountingEnumHeuristicfalse

enum TagWithCounter {
  Tag1,
  Tag2,
  Tag3,
  TagCount,
};

struct TaggedUnion {
  TagWithCounter Kind;
  union {
    int A;
    long B;
    char *Str;
    float F;
  } Data;
};

EnableCountingEnumHeuristictrue

enum TagWithCounter {
  Tag1,
  Tag2,
  Tag3,
  TagCount,
};

struct TaggedUnion { // warning: tagged union has more data members (4) than tags (3)
  TagWithCounter Kind;
  union {
    int A;
    long B;
    char *Str;
    float F;
  } Data;
};
CountingEnumPrefixes

请参阅下面的 CountingEnumSuffixes

CountingEnumSuffixes

CountingEnumPrefixes 和 CountingEnumSuffixes 是用于搜索可能的枚举计数常量的以分号分隔的字符串列表。这些字符串不区分大小写,分别作为前缀和后缀匹配枚举常量的名称。如果 EnableCountingEnumHeuristicfalse,则这些选项无效。

CountingEnumSuffixes 的默认值为 countCountingEnumPrefixes 的默认值为空字符串。

EnableCountingEnumHeuristictrueCountingEnumSuffixescount;size

enum TagWithCounterCount {
  Tag1,
  Tag2,
  Tag3,
  TagCount,
};

struct TaggedUnionCount { // warning: tagged union has more data members (4) than tags (3)
  TagWithCounterCount Kind;
  union {
    int A;
    long B;
    char *Str;
    float F;
  } Data;
};

enum TagWithCounterSize {
  Tag11,
  Tag22,
  Tag33,
  TagSize,
};

struct TaggedUnionSize { // warning: tagged union has more data members (4) than tags (3)
  TagWithCounterSize Kind;
  union {
    int A;
    long B;
    char *Str;
    float F;
  } Data;
};

EnableCountingEnumHeuristictrueCountingEnumPrefixesmaxsize;last_

enum TagWithCounterLast {
  Tag1,
  Tag2,
  Tag3,
  last_tag,
};

struct TaggedUnionLast { // warning: tagged union has more data members (4) than tags (3)
  TagWithCounterLast tag;
  union {
    int I;
    short S;
    char *C;
    float F;
  } Data;
};

enum TagWithCounterMaxSize {
  Tag1,
  Tag2,
  Tag3,
  MaxSizeTag,
};

struct TaggedUnionMaxSize { // warning: tagged union has more data members (4) than tags (3)
  TagWithCounterMaxSize tag;
  union {
    int I;
    short S;
    char *C;
    float F;
  } Data;
};
StrictMode

启用后,检查还会发出警告,如果标记的数量大于联合体成员数据的数量。

此选项默认禁用。

StrictModefalse

struct TaggedUnion {
  enum {
    Tag1,
    Tag2,
    Tag3,
  } Tags;
  union {
    int I;
    float F;
  } Data;
};

StrictModetrue

struct TaggedUnion { // warning: tagged union has fewer data members (2) than tags (3)
  enum {
    Tag1,
    Tag2,
    Tag3,
  } Tags;
  union {
    int I;
    float F;
  } Data;
};