================
@@ -0,0 +1,163 @@
+//===--- UseToUnderlyingCheck.cpp - clang-tidy
----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseToUnderlyingCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy {
+
+template <>
+struct OptionEnumMapping<modernize::UseToUnderlyingCheck::ImpreciseCastsKind> {
+ static llvm::ArrayRef<
+ std::pair<modernize::UseToUnderlyingCheck::ImpreciseCastsKind,
StringRef>>
+ getEnumMapping() {
+ using ImpreciseCastsKind =
+ modernize::UseToUnderlyingCheck::ImpreciseCastsKind;
+ static constexpr std::pair<ImpreciseCastsKind, StringRef> Mapping[] = {
+ {ImpreciseCastsKind::Ignore, "Ignore"},
+ {ImpreciseCastsKind::Warn, "Warn"},
+ {ImpreciseCastsKind::PreserveType, "PreserveType"},
+ {ImpreciseCastsKind::UseUnderlyingType, "UseUnderlyingType"},
+ };
+ return {Mapping};
+ }
+};
+
+} // namespace clang::tidy
+
+namespace clang::tidy::modernize {
+
+UseToUnderlyingCheck::UseToUnderlyingCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ ImpreciseCasts(Options.get("ImpreciseCasts", ImpreciseCastsKind::Warn)),
+ ReplacementFunction(
+ Options.get("ReplacementFunction", "std::to_underlying")),
+ IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+ utils::IncludeSorter::IS_LLVM),
+ areDiagsSelfContained()),
+ MaybeHeaderToInclude(Options.get("ReplacementFunctionHeader")) {
+ if (!MaybeHeaderToInclude && ReplacementFunction == "std::to_underlying")
+ MaybeHeaderToInclude = "<utility>";
+}
+
+bool UseToUnderlyingCheck::isLanguageVersionSupported(
+ const LangOptions &LangOpts) const {
+ // std::to_underlying is a C++23 library facility, but a user-provided
+ // replacement (e.g. llvm::to_underlying) only requires scoped enumerations,
+ // which are available since C++11.
+ if (ReplacementFunction == "std::to_underlying")
+ return LangOpts.CPlusPlus23;
+ return LangOpts.CPlusPlus11;
+}
+
+void UseToUnderlyingCheck::registerPPCallbacks(const SourceManager &SM,
+ Preprocessor *PP,
+ Preprocessor *ModuleExpanderPP)
{
+ IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseToUnderlyingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "ImpreciseCasts", ImpreciseCasts);
+ Options.store(Opts, "ReplacementFunction", ReplacementFunction);
+ Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+ if (MaybeHeaderToInclude)
+ Options.store(Opts, "ReplacementFunctionHeader", *MaybeHeaderToInclude);
+}
+
+void UseToUnderlyingCheck::registerMatchers(MatchFinder *Finder) {
+ // Match an explicit cast (``static_cast``, C-style or functional) whose
+ // operand is an expression of scoped-enumeration type. The destination type
+ // is validated in check() so that the same code path handles precise and
+ // imprecise conversions.
+ Finder->addMatcher(
+ explicitCastExpr(
+ unless(isInTemplateInstantiation()),
+ hasSourceExpression(
+ expr(hasType(hasCanonicalType(enumType(
+ hasDeclaration(enumDecl(isScoped()).bind("enum"))))))
+ .bind("operand")))
+ .bind("cast"),
+ this);
+}
+
+void UseToUnderlyingCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Cast = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast");
+ const auto *Operand = Result.Nodes.getNodeAs<Expr>("operand");
+ const auto *Enum = Result.Nodes.getNodeAs<EnumDecl>("enum");
+
+ // Ignore dependent contexts we cannot reason about reliably.
+ if (Cast->isValueDependent() || Cast->getType()->isDependentType())
+ return;
+
+ const QualType DestType = Cast->getType().getCanonicalType();
+
+ // We only care about conversions to an integer type. Enum-to-enum casts and
+ // floating-point or pointer destinations are excluded.
+ if (!DestType->isIntegerType() || DestType->isEnumeralType())
+ return;
----------------
zwuis wrote:
I don't think we need to check for value-dependence. We can just treat them
like plain variables, without caring about their exact values.
Move other conditions to AST matchers.
```cpp
castExpr(
...,
hasType(/* your matchers */))
```
https://github.com/llvm/llvm-project/pull/210459
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits