12#include "clang/AST/ASTContext.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
26AST_MATCHER(EnumDecl, hasEnumerators) {
return !Node.enumerators().empty(); }
28const std::uint64_t Min8 =
29 std::imaxabs(std::numeric_limits<std::int8_t>::min());
30const std::uint64_t Max8 = std::numeric_limits<std::int8_t>::max();
31const std::uint64_t Min16 =
32 std::imaxabs(std::numeric_limits<std::int16_t>::min());
33const std::uint64_t Max16 = std::numeric_limits<std::int16_t>::max();
34const std::uint64_t Min32 =
35 std::imaxabs(std::numeric_limits<std::int32_t>::min());
36const std::uint64_t Max32 = std::numeric_limits<std::int32_t>::max();
39static std::pair<const char *, std::uint32_t>
40getNewType(std::size_t Size, std::uint64_t Min, std::uint64_t Max)
noexcept {
42 if (Min <= Min8 && Max <= Max8) {
43 return {
"std::int8_t",
sizeof(std::int8_t)};
46 if (Min <= Min16 && Max <= Max16 && Size >
sizeof(std::int16_t)) {
47 return {
"std::int16_t",
sizeof(std::int16_t)};
50 if (Min <= Min32 && Max <= Max32 && Size >
sizeof(std::int32_t)) {
51 return {
"std::int32_t",
sizeof(std::int32_t)};
58 if (Max <= std::numeric_limits<std::uint8_t>::max()) {
59 return {
"std::uint8_t",
sizeof(std::uint8_t)};
62 if (Max <= std::numeric_limits<std::uint16_t>::max() &&
63 Size >
sizeof(std::uint16_t)) {
64 return {
"std::uint16_t",
sizeof(std::uint16_t)};
67 if (Max <= std::numeric_limits<std::uint32_t>::max() &&
68 Size >
sizeof(std::uint32_t)) {
69 return {
"std::uint32_t",
sizeof(std::uint32_t)};
76 return {
"std::uint8_t",
sizeof(std::uint8_t)};
82 utils::options::parseStringList(Options.get(
"EnumIgnoreList",
""))) {}
85 Options.store(Opts,
"EnumIgnoreList",
90 const LangOptions &LangOpts)
const {
91 return LangOpts.CPlusPlus11;
96 enumDecl(unless(isExpansionInSystemHeader()), isDefinition(),
104 const auto *MatchedDecl = Result.Nodes.getNodeAs<EnumDecl>(
"e");
105 const QualType BaseType = MatchedDecl->getIntegerType().getCanonicalType();
106 if (!BaseType->isIntegerType())
109 const std::uint32_t Size = Result.Context->getTypeSize(BaseType) / 8U;
113 std::uint64_t MinV = 0U;
114 std::uint64_t MaxV = 0U;
116 for (
const auto &It : MatchedDecl->enumerators()) {
117 const llvm::APSInt &InitVal = It->getInitVal();
118 if ((InitVal.isUnsigned() || InitVal.isNonNegative())) {
119 MaxV = std::max<std::uint64_t>(MaxV, InitVal.getZExtValue());
121 MinV = std::max<std::uint64_t>(MinV, InitVal.abs().getZExtValue());
126 if (!NewType.first || Size <= NewType.second)
129 diag(MatchedDecl->getLocation(),
130 "enum %0 uses a larger base type (%1, size: %2 %select{byte|bytes}5) "
131 "than necessary for its value set, consider using '%3' (%4 "
132 "%select{byte|bytes}6) as the base type to reduce its size")
133 << MatchedDecl << MatchedDecl->getIntegerType() << Size << NewType.first
134 << NewType.second << (Size > 1U) << (NewType.second > 1U);
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
AST_MATCHER(BinaryOperator, isRelationalOperator)
inline ::clang::ast_matchers::internal::Matcher< NamedDecl > matchesAnyListedName(llvm::ArrayRef< StringRef > NameList)
std::string serializeStringList(ArrayRef< StringRef > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
llvm::StringMap< ClangTidyValue > OptionMap