llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-tools-extra

Author: Lucas Ly Ba (lucasly-ba)

<details>
<summary>Changes</summary>

Replaces a static_cast that only adds const to an lvalue with a call to 
std::as_const (C++17), which states the intent more clearly and cannot 
accidentally change the referenced type. The fix also inserts the 
&lt;utility&gt; include.

Fixes #<!-- -->189665

---
Full diff: https://github.com/llvm/llvm-project/pull/210554.diff


8 Files Affected:

- (modified) clang-tools-extra/clang-tidy/modernize/CMakeLists.txt (+1) 
- (modified) clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
(+3) 
- (added) clang-tools-extra/clang-tidy/modernize/UseAsConstCheck.cpp (+77) 
- (added) clang-tools-extra/clang-tidy/modernize/UseAsConstCheck.h (+43) 
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+6) 
- (modified) clang-tools-extra/docs/clang-tidy/checks/list.rst (+1) 
- (added) clang-tools-extra/docs/clang-tidy/checks/modernize/use-as-const.rst 
(+29) 
- (added) clang-tools-extra/test/clang-tidy/checkers/modernize/use-as-const.cpp 
(+19) 


``````````diff
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index 2c5c44db587fe..78e9c02b16255 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -31,6 +31,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   ShrinkToFitCheck.cpp
   TypeTraitsCheck.cpp
   UnaryStaticAssertCheck.cpp
+  UseAsConstCheck.cpp
   UseAutoCheck.cpp
   UseBoolLiteralsCheck.cpp
   UseConstraintsCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index cc13da7535bcb..abeff9e72e117 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -31,6 +31,7 @@
 #include "ShrinkToFitCheck.h"
 #include "TypeTraitsCheck.h"
 #include "UnaryStaticAssertCheck.h"
+#include "UseAsConstCheck.h"
 #include "UseAutoCheck.h"
 #include "UseBoolLiteralsCheck.h"
 #include "UseConstraintsCheck.h"
@@ -88,6 +89,8 @@ class ModernizeModule : public ClangTidyModule {
     CheckFactories.registerCheck<MinMaxUseInitializerListCheck>(
         "modernize-min-max-use-initializer-list");
     CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
+    CheckFactories.registerCheck<UseAsConstCheck>(
+        "modernize-use-as-const");
     CheckFactories.registerCheck<UseDesignatedInitializersCheck>(
         "modernize-use-designated-initializers");
     CheckFactories.registerCheck<UseIntegerSignComparisonCheck>(
diff --git a/clang-tools-extra/clang-tidy/modernize/UseAsConstCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseAsConstCheck.cpp
new file mode 100644
index 0000000000000..8fb7a36d904e5
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseAsConstCheck.cpp
@@ -0,0 +1,77 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "UseAsConstCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+UseAsConstCheck::UseAsConstCheck(StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      Inserter(Options.getLocalOrGlobal("IncludeStyle",
+                                        utils::IncludeSorter::IS_LLVM),
+               areDiagsSelfContained()) {}
+
+void UseAsConstCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "IncludeStyle", Inserter.getStyle());
+}
+
+void UseAsConstCheck::registerMatchers(MatchFinder *Finder) {
+  // The result of a cast to 'const T &' is a const-qualified lvalue.
+  Finder->addMatcher(
+      cxxStaticCastExpr(hasType(qualType(isConstQualified()))).bind("cast"),
+      this);
+}
+
+void UseAsConstCheck::registerPPCallbacks(const SourceManager &SM,
+                                          Preprocessor *PP,
+                                          Preprocessor *ModuleExpanderPP) {
+  Inserter.registerPreprocessor(PP);
+}
+
+void UseAsConstCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Cast = Result.Nodes.getNodeAs<CXXStaticCastExpr>("cast");
+  if (Cast->getBeginLoc().isMacroID())
+    return;
+
+  // The cast must be written as 'const T &'.
+  const auto *RefType = Cast->getTypeAsWritten()->getAs<LValueReferenceType>();
+  if (!RefType || !RefType->getPointeeType().isConstQualified())
+    return;
+
+  const Expr *Sub = Cast->getSubExprAsWritten();
+  if (!Sub->isLValue())
+    return;
+
+  // Only rewrite when the cast just adds 'const' to the same type; that is
+  // exactly what std::as_const does.
+  ASTContext &Ctx = *Result.Context;
+  QualType SubType = Sub->getType();
+  if (SubType.isConstQualified() ||
+      !Ctx.hasSameUnqualifiedType(SubType, RefType->getPointeeType()))
+    return;
+
+  const SourceManager &SM = *Result.SourceManager;
+  StringRef SubText = Lexer::getSourceText(
+      CharSourceRange::getTokenRange(Sub->getSourceRange()), SM, 
getLangOpts());
+  if (SubText.empty())
+    return;
+
+  diag(Cast->getBeginLoc(),
+       "use 'std::as_const' instead of 'static_cast' to add 'const'")
+      << FixItHint::CreateReplacement(
+             Cast->getSourceRange(), ("std::as_const(" + SubText + ")").str())
+      << Inserter.createIncludeInsertion(SM.getFileID(Cast->getBeginLoc()),
+                                         "<utility>");
+}
+
+} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseAsConstCheck.h 
b/clang-tools-extra/clang-tidy/modernize/UseAsConstCheck.h
new file mode 100644
index 0000000000000..145875df06cac
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseAsConstCheck.h
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEASCONSTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEASCONSTCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "../utils/IncludeInserter.h"
+
+namespace clang::tidy::modernize {
+
+/// Suggests ``std::as_const`` for a ``static_cast`` that only adds ``const`` 
to
+/// an lvalue, e.g. ``static_cast<const T &>(x)`` becomes ``std::as_const(x)``.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-as-const.html
+class UseAsConstCheck : public ClangTidyCheck {
+public:
+  UseAsConstCheck(StringRef Name, ClangTidyContext *Context);
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+                           Preprocessor *ModuleExpanderPP) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus17;
+  }
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
+
+private:
+  utils::IncludeInserter Inserter;
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEASCONSTCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 69c3bcf67b8db..243b956b5c2fe 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -97,6 +97,12 @@ Improvements to clang-tidy
 New checks
 ^^^^^^^^^^
 
+- New :doc:`modernize-use-as-const
+  <clang-tidy/checks/modernize/use-as-const>` check.
+
+  Replaces a ``static_cast`` that only adds ``const`` to an lvalue with a call
+  to ``std::as_const``.
+
 New check aliases
 ^^^^^^^^^^^^^^^^^
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst 
b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 2a44dc78fbc89..24613445f3205 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -312,6 +312,7 @@ Clang-Tidy Checks
    :doc:`modernize-shrink-to-fit <modernize/shrink-to-fit>`, "Yes"
    :doc:`modernize-type-traits <modernize/type-traits>`, "Yes"
    :doc:`modernize-unary-static-assert <modernize/unary-static-assert>`, "Yes"
+   :doc:`modernize-use-as-const <modernize/use-as-const>`, "Yes"
    :doc:`modernize-use-auto <modernize/use-auto>`, "Yes"
    :doc:`modernize-use-bool-literals <modernize/use-bool-literals>`, "Yes"
    :doc:`modernize-use-constraints <modernize/use-constraints>`, "Yes"
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-as-const.rst 
b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-as-const.rst
new file mode 100644
index 0000000000000..bd75a49c7b431
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-as-const.rst
@@ -0,0 +1,29 @@
+.. title:: clang-tidy - modernize-use-as-const
+
+modernize-use-as-const
+======================
+
+Replaces a ``static_cast`` that only adds ``const`` to an lvalue with a call to
+``std::as_const`` (available since C++17), which states the intent more clearly
+and cannot accidentally change the referenced type.
+
+.. code-block:: c++
+
+  void use(const std::string &);
+
+  void f(std::string s) {
+    use(static_cast<const std::string &>(s));
+  }
+
+becomes
+
+.. code-block:: c++
+
+  void use(const std::string &);
+
+  void f(std::string s) {
+    use(std::as_const(s));
+  }
+
+Casts of an already ``const`` operand, and casts that change the type rather 
than
+only adding ``const``, are left untouched.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-as-const.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-as-const.cpp
new file mode 100644
index 0000000000000..d1de8e765f073
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-as-const.cpp
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy -std=c++17 %s modernize-use-as-const %t
+
+// CHECK-FIXES: #include <utility>
+
+struct S {};
+void use(const S &);
+
+void positive(S obj) {
+  use(static_cast<const S &>(obj));
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use 'std::as_const' instead of 
'static_cast' to add 'const' [modernize-use-as-const]
+  // CHECK-FIXES: use(std::as_const(obj));
+}
+
+void negative(const S cobj, S obj) {
+  // Already const: nothing to add.
+  use(static_cast<const S &>(cobj));
+  // Casts to a different type are not just adding const.
+  use(obj);
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/210554
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to