PiotrZSL created this revision.
PiotrZSL added reviewers: carlosgalvezp, njames93.
Herald added a subscriber: xazax.hun.
Herald added a project: All.
PiotrZSL requested review of this revision.
Herald added subscribers: cfe-commits, wangpc.
Herald added a project: clang-tools-extra.

New option added and configured in a way, so types
related to std::strong_ordering would be ignored.

Fixes: #63478


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D158928

Files:
  clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
  clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
  clang-tools-extra/clang-tidy/utils/Matchers.cpp
  clang-tools-extra/clang-tidy/utils/Matchers.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/modernize/use-nullptr.rst
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-cxx20.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-cxx20.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-cxx20.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-cxx20.cpp
@@ -1,35 +1,51 @@
-// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t -- -- -DGCC
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t -- -- -DCLANG
 
 namespace std {
 class strong_ordering;
 
 // Mock how STD defined unspecified parameters for the operators below.
+#ifdef CLANG
 struct _CmpUnspecifiedParam {
   consteval
   _CmpUnspecifiedParam(int _CmpUnspecifiedParam::*) noexcept {}
 };
 
+#define UNSPECIFIED_TYPE _CmpUnspecifiedParam
+#endif
+
+#ifdef GCC
+namespace __cmp_cat {
+  struct __unspec {
+    constexpr __unspec(__unspec*) noexcept { }
+  };
+}
+
+#define UNSPECIFIED_TYPE __cmp_cat::__unspec
+#endif
+
 struct strong_ordering {
   signed char value;
 
   friend constexpr bool operator==(strong_ordering v,
-                                   _CmpUnspecifiedParam) noexcept {
+                                   UNSPECIFIED_TYPE) noexcept {
     return v.value == 0;
   }
   friend constexpr bool operator<(strong_ordering v,
-                                  _CmpUnspecifiedParam) noexcept {
+                                  UNSPECIFIED_TYPE) noexcept {
     return v.value < 0;
   }
   friend constexpr bool operator>(strong_ordering v,
-                                  _CmpUnspecifiedParam) noexcept {
+                                  UNSPECIFIED_TYPE) noexcept {
     return v.value > 0;
   }
   friend constexpr bool operator>=(strong_ordering v,
-                                   _CmpUnspecifiedParam) noexcept {
+                                   UNSPECIFIED_TYPE) noexcept {
     return v.value >= 0;
   }
   static const strong_ordering equal, greater, less;
 };
+
 constexpr strong_ordering strong_ordering::equal = {0};
 constexpr strong_ordering strong_ordering::greater = {1};
 constexpr strong_ordering strong_ordering::less = {-1};
@@ -59,6 +75,13 @@
   // CHECK-FIXES: result = (a1 > ((a1 > (ptr == nullptr ? a1 : a2)) ? a1 : a2));
 }
 
+void testValidZero() {
+  A a1, a2;
+  auto result = a1 <=> a2;
+  if (result < 0) {}
+  // CHECK-FIXES: if (result < 0) {}
+}
+
 template<class T1, class T2>
 struct P {
   T1 x1;
Index: clang-tools-extra/docs/clang-tidy/checks/modernize/use-nullptr.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/modernize/use-nullptr.rst
+++ clang-tools-extra/docs/clang-tidy/checks/modernize/use-nullptr.rst
@@ -39,6 +39,12 @@
 Options
 -------
 
+.. option:: IgnoredTypes
+
+  Semicolon-separated list of regular expressions to match pointer types for
+  which implicit casts will be ignored. Default value:
+  `std::_CmpUnspecifiedParam::;^std::__cmp_cat::__unspec`.
+
 .. option:: NullMacros
 
    Comma-separated list of macro names that will be transformed along with
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -230,6 +230,10 @@
   <clang-tidy/checks/modernize/loop-convert>` to support for-loops with
   iterators initialized by free functions like ``begin``, ``end``, or ``size``.
 
+- Improved :doc:`modernize-use-nullptr
+  <clang-tidy/checks/modernize/use-nullptr>` check by adding option
+  `IgnoredTypes` that can be used to exclude some pointer types.
+
 - Improved :doc:`performance-faster-string-find
   <clang-tidy/checks/performance/faster-string-find>` check to properly escape
   single quotes.
Index: clang-tools-extra/clang-tidy/utils/Matchers.h
===================================================================
--- clang-tools-extra/clang-tidy/utils/Matchers.h
+++ clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -158,6 +158,28 @@
   return Builder->removeBindings(Predicate);
 }
 
+// A matcher implementation that matches a list of type name regular expressions
+// against a QualType.
+class MatchesAnyListedTypeNameMatcher
+    : public ast_matchers::internal::MatcherInterface<QualType> {
+public:
+  explicit MatchesAnyListedTypeNameMatcher(llvm::ArrayRef<StringRef> NameList);
+  ~MatchesAnyListedTypeNameMatcher() override;
+  bool matches(
+      const QualType &Node, ast_matchers::internal::ASTMatchFinder *Finder,
+      ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override;
+
+private:
+  std::vector<llvm::Regex> NameMatchers;
+};
+
+// Returns a matcher that matches QualType against a list of provided regular.
+inline ::clang::ast_matchers::internal::Matcher<QualType>
+matchesAnyListedTypeName(llvm::ArrayRef<StringRef> NameList) {
+  return ::clang::ast_matchers::internal::makeMatcher(
+      new MatchesAnyListedTypeNameMatcher(NameList));
+}
+
 } // namespace clang::tidy::matchers
 
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H
Index: clang-tools-extra/clang-tidy/utils/Matchers.cpp
===================================================================
--- clang-tools-extra/clang-tidy/utils/Matchers.cpp
+++ clang-tools-extra/clang-tidy/utils/Matchers.cpp
@@ -17,4 +17,32 @@
                                         Nodes.getNodeAs<Stmt>(ID), *Context);
 }
 
+MatchesAnyListedTypeNameMatcher::MatchesAnyListedTypeNameMatcher(
+    llvm::ArrayRef<StringRef> NameList)
+    : NameMatchers(NameList.begin(), NameList.end()) {}
+
+MatchesAnyListedTypeNameMatcher::~MatchesAnyListedTypeNameMatcher() = default;
+
+bool MatchesAnyListedTypeNameMatcher::matches(
+    const QualType &Node, ast_matchers::internal::ASTMatchFinder *Finder,
+    ast_matchers::internal::BoundNodesTreeBuilder *Builder) const {
+
+  if (NameMatchers.empty())
+    return false;
+
+  PrintingPolicy PrintingPolicyWithSuppressedTag(
+      Finder->getASTContext().getLangOpts());
+  PrintingPolicyWithSuppressedTag.PrintCanonicalTypes = true;
+  PrintingPolicyWithSuppressedTag.SuppressElaboration = true;
+  PrintingPolicyWithSuppressedTag.SuppressScope = false;
+  PrintingPolicyWithSuppressedTag.SuppressTagKeyword = true;
+  PrintingPolicyWithSuppressedTag.SuppressUnwrittenScope = true;
+  std::string TypeName =
+      Node.getUnqualifiedType().getAsString(PrintingPolicyWithSuppressedTag);
+
+  return llvm::any_of(NameMatchers, [&TypeName](const llvm::Regex &NM) {
+    return NM.isValid() && NM.match(TypeName);
+  });
+}
+
 } // namespace clang::tidy::matchers
Index: clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
===================================================================
--- clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
+++ clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
@@ -28,6 +28,7 @@
 private:
   const StringRef NullMacrosStr;
   SmallVector<StringRef, 1> NullMacros;
+  std::vector<StringRef> IgnoredTypes;
 };
 
 } // namespace clang::tidy::modernize
Index: clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -7,6 +7,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "UseNullptrCheck.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
@@ -33,11 +35,13 @@
 /// to null within.
 /// Finding sequences of explicit casts is necessary so that an entire sequence
 /// can be replaced instead of just the inner-most implicit cast.
-StatementMatcher makeCastSequenceMatcher() {
-  StatementMatcher ImplicitCastToNull = implicitCastExpr(
+StatementMatcher makeCastSequenceMatcher(llvm::ArrayRef<StringRef> NameList) {
+  auto ImplicitCastToNull = implicitCastExpr(
       anyOf(hasCastKind(CK_NullToPointer), hasCastKind(CK_NullToMemberPointer)),
       unless(hasImplicitDestinationType(qualType(substTemplateTypeParmType()))),
-      unless(hasSourceExpression(hasType(sugaredNullptrType()))));
+      unless(hasSourceExpression(hasType(sugaredNullptrType()))),
+      unless(hasImplicitDestinationType(
+          qualType(matchers::matchesAnyListedTypeName(NameList)))));
 
   auto IsOrHasDescendant = [](auto InnerMatcher) {
     return anyOf(InnerMatcher, hasDescendant(InnerMatcher));
@@ -480,16 +484,21 @@
 
 UseNullptrCheck::UseNullptrCheck(StringRef Name, ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
-      NullMacrosStr(Options.get("NullMacros", "NULL")) {
+      NullMacrosStr(Options.get("NullMacros", "NULL")),
+      IgnoredTypes(utils::options::parseStringList(Options.get(
+          "IgnoredTypes",
+          "std::_CmpUnspecifiedParam::;^std::__cmp_cat::__unspec"))) {
   StringRef(NullMacrosStr).split(NullMacros, ",");
 }
 
 void UseNullptrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "NullMacros", NullMacrosStr);
+  Options.store(Opts, "IgnoredTypes",
+                utils::options::serializeStringList(IgnoredTypes));
 }
 
 void UseNullptrCheck::registerMatchers(MatchFinder *Finder) {
-  Finder->addMatcher(makeCastSequenceMatcher(), this);
+  Finder->addMatcher(makeCastSequenceMatcher(IgnoredTypes), this);
 }
 
 void UseNullptrCheck::check(const MatchFinder::MatchResult &Result) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to