[clang-tools-extra] [clang-tidy] Add `modernize-use-uniform-initializer` check (PR #91124)

Piotr Zegar via cfe-commits cfe-commits at lists.llvm.org
Sun May 5 09:14:30 PDT 2024


================
@@ -0,0 +1,320 @@
+//===--- UseUniformInitializerCheck.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 "UseUniformInitializerCheck.h"
+#include "../utils/LexerUtils.h"
+#include "clang/Tooling/FixIt.h"
+
+AST_MATCHER(clang::VarDecl, isVarOldStyleInitializer) {
+  // If it doesn't have any initializer the initializer style is not defined.
+  if (!Node.hasInit())
+    return false;
+
+  const clang::VarDecl::InitializationStyle InitStyle = Node.getInitStyle();
+
+  return InitStyle == clang::VarDecl::InitializationStyle::CInit ||
+         InitStyle == clang::VarDecl::InitializationStyle::CallInit;
+}
+
+AST_MATCHER(clang::FieldDecl, isFieldOldStyleInitializer) {
+  // If it doesn't have any initializer the initializer style is not defined.
+  if (!Node.hasInClassInitializer() || Node.getInClassInitializer() == nullptr)
+    return false;
+
+  const clang::InClassInitStyle InitStyle = Node.getInClassInitStyle();
+
+  return InitStyle == clang::InClassInitStyle::ICIS_CopyInit;
+}
+
+AST_MATCHER(clang::CXXCtorInitializer, isCStyleInitializer) {
+  const clang::Expr *Init = Node.getInit();
+  if (Init == nullptr)
+    return false;
+
+  return !llvm::isa<clang::InitListExpr>(Init);
+}
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+namespace {
+
+constexpr const StringRef VarDeclID = "VarDecl";
+constexpr const StringRef FieldDeclId = "FieldDecl";
+constexpr const StringRef CtorInitID = "CtorInit";
+
+constexpr const StringRef CStyleWarningMessage =
+    "Use uniform initializer instead of C-style initializer";
+
+constexpr StringRef
+getInitializerStyleName(VarDecl::InitializationStyle InitStyle) {
+  switch (InitStyle) {
+  case VarDecl::InitializationStyle::CInit:
+    return "C";
+
+  case VarDecl::InitializationStyle::CallInit:
+    return "call";
+
+  default:
+    llvm_unreachable("Invalid initializer style!");
+  }
+}
+
+SourceRange getParenLocationsForCallInit(const Expr *InitExpr,
+                                         const SourceManager &SM,
+                                         const LangOptions &LangOpts) {
+  // We need to handle 'CXXConstructExpr' differently
+  if (isa<CXXConstructExpr>(InitExpr))
+    return cast<CXXConstructExpr>(InitExpr)->getParenOrBraceRange();
+
+  // If the init expression itself is a 'ParenExpr' then
+  // 'InitExpr->getBeginLoc()' will already point to a '(' which is not the
+  // opening paren of the 'CallInit' expression. So it that case we need to
+  // start one character before that.
+  const bool NeedOffsetForOpenParen = [&]() {
+    if (!isa<ParenExpr>(InitExpr))
+      return false;
+
+    const clang::StringRef CharBeforeParenExpr =
+        Lexer::getSourceText(CharSourceRange::getCharRange(
+                                 InitExpr->getBeginLoc().getLocWithOffset(-1),
+                                 InitExpr->getBeginLoc()),
+                             SM, LangOpts);
+
+    return llvm::isSpace(CharBeforeParenExpr[0]);
+  }();
+
+  const SourceLocation OpenParenLoc = utils::lexer::findPreviousTokenKind(
+      NeedOffsetForOpenParen ? InitExpr->getBeginLoc().getLocWithOffset(-1)
+                             : InitExpr->getBeginLoc(),
+      SM, LangOpts, tok::l_paren);
+  const SourceLocation CloseParenLoc = utils::lexer::findNextTokenKind(
+      InitExpr->getEndLoc(), SM, LangOpts, tok::r_paren);
+
+  return {OpenParenLoc, CloseParenLoc};
+}
+
+const BuiltinType *getBuiltinType(const Expr *Expr) {
+  assert(Expr);
+  return Expr->getType().getCanonicalType().getTypePtr()->getAs<BuiltinType>();
+}
+
+bool castRequiresStaticCast(const ImplicitCastExpr *CastExpr) {
+  const auto *FromExpr = CastExpr->getSubExpr();
+
+  if (CastExpr->isInstantiationDependent() ||
+      FromExpr->isInstantiationDependent())
+    return false;
+  if (getBuiltinType(CastExpr) == getBuiltinType(FromExpr))
+    return false;
+
+  switch (CastExpr->getCastKind()) {
+  case CastKind::CK_BaseToDerived:
+  case CastKind::CK_DerivedToBaseMemberPointer:
+  case CastKind::CK_IntegralCast:
+  case CastKind::CK_FloatingToIntegral:
+    return true;
+
+  default:
+    return false;
+  }
+}
+
+std::string buildReplacementString(const Expr *InitExpr,
+                                   const ASTContext &Context) {
+  // TODO: This function does not correctly handle the case where you have in
+  // 'ImplicitCastExpr' as an argument for a 'CXXConstructExpr'.
+  // In that case the generated code will not compile due to missing explicit
+  // cast of the sub expression.
+
+  const SourceManager &SM = Context.getSourceManager();
+  const LangOptions &LangOpts = Context.getLangOpts();
+
+  const StringRef InitExprStr = [&]() {
+    if (isa<CXXConstructExpr>(InitExpr)) {
+      const auto *ConstructExpr = llvm::cast<CXXConstructExpr>(InitExpr);
+
+      const SourceRange ParenRange = ConstructExpr->getParenOrBraceRange();
+      if (ParenRange.isValid())
+        return Lexer::getSourceText(
+                   CharSourceRange::getCharRange(
+                       ParenRange.getBegin().getLocWithOffset(1),
+                       ParenRange.getEnd()),
+                   SM, LangOpts)
+            .trim();
+
+      // In case the ParenRange is invalid we use Begin/EndLoc
+      const SourceLocation BeginLocation = ConstructExpr->getBeginLoc();
+      const SourceLocation EndLocation = ConstructExpr->getEndLoc();
+
+      return Lexer::getSourceText(
+                 CharSourceRange::getCharRange(BeginLocation,
+                                               EndLocation.getLocWithOffset(1)),
+                 SM, LangOpts)
+          .trim();
+    }
+
+    return tooling::fixit::getText(*InitExpr, Context);
+  }();
+
+  // For some 'ImplicitCastExpr' we need to add an extra 'static_cast<T>' around
+  // the expression since implicit conversions are not allowed with uniform
+  // initializer and otherwise will lead to compile errors
+  if (isa<ImplicitCastExpr>(InitExpr)) {
+    const auto *CastExpr = llvm::cast<ImplicitCastExpr>(InitExpr);
----------------
PiotrZSL wrote:

dyn_cast  +if

https://github.com/llvm/llvm-project/pull/91124


More information about the cfe-commits mailing list