poelmanc updated this revision to Diff 320284.
poelmanc added a comment.

Fix test failure in `modernize-use-nullptr-cxx20.cpp` by replacing `#include 
<compare>` with some minimal equivalent `std` code.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95726/new/

https://reviews.llvm.org/D95726

Files:
  clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/include/clang/ASTMatchers/ASTMatchersInternal.h
  clang/lib/ASTMatchers/ASTMatchFinder.cpp

Index: clang/lib/ASTMatchers/ASTMatchFinder.cpp
===================================================================
--- clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -659,6 +659,8 @@
       ResultCache.clear();
     if (MatchMode == AncestorMatchMode::AMM_ParentOnly)
       return matchesParentOf(Node, Matcher, Builder);
+    else if (MatchMode == AncestorMatchMode::AMM_GrandparentOnly)
+      return matchesGrandparentOf(Node, Matcher, Builder);
     return matchesAnyAncestorOf(Node, Ctx, Matcher, Builder);
   }
 
@@ -893,6 +895,18 @@
     return false;
   }
 
+  // Returns whether a direct grandparent of \p Node matches \p Matcher.
+  bool matchesGrandparentOf(const DynTypedNode &Node,
+                                  const DynTypedMatcher &Matcher,
+                                  BoundNodesTreeBuilder *Builder) {
+    for (const auto &Parent : ActiveASTContext->getParents(Node)) {
+      if (matchesParentOf(Parent, Matcher, Builder)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   // Returns whether an ancestor of \p Node matches \p Matcher.
   //
   // The order of matching (which can lead to different nodes being bound in
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -654,7 +654,10 @@
     AMM_All,
 
     /// Direct parent only.
-    AMM_ParentOnly
+    AMM_ParentOnly,
+
+    /// Direct grandparent only.
+    AMM_GrandparentOnly
   };
 
   virtual ~ASTMatchFinder() = default;
@@ -1654,6 +1657,29 @@
   }
 };
 
+/// Matches nodes of type \c T that have a grandparent node of type
+/// \c GrandparentT for which the given inner matcher matches.
+///
+/// \c GrandparentT must be an AST base type.
+template <typename T, typename GrandparentT>
+class HasGrandparentMatcher : public MatcherInterface<T> {
+  static_assert(IsBaseType<GrandparentT>::value,
+                "has parent only accepts base type matcher");
+
+  const DynTypedMatcher GrandparentMatcher;
+
+public:
+  explicit HasGrandparentMatcher(
+      const Matcher<GrandparentT> &GrandparentMatcher)
+      : GrandparentMatcher(GrandparentMatcher) {}
+
+  bool matches(const T &Node, ASTMatchFinder *Finder,
+               BoundNodesTreeBuilder *Builder) const override {
+    return Finder->matchesAncestorOf(Node, this->GrandparentMatcher, Builder,
+                                     ASTMatchFinder::AMM_GrandparentOnly);
+  }
+};
+
 /// Matches nodes of type \c T that have at least one ancestor node of
 /// type \c AncestorT for which the given inner matcher matches.
 ///
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -3434,6 +3434,22 @@
     internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>>
     hasParent;
 
+/// Matches AST nodes that have a grandparent that matches the provided
+/// matcher.
+///
+/// Given
+/// \code
+/// void f() { for (;;) { int x = 42; if (true) { int x = 43; } } }
+/// \endcode
+/// \c compoundStmt(hasGrandparent(forStmt())) matches "{ int x = 43; }".
+///
+/// Usable as: Any Matcher
+extern const internal::ArgumentAdaptingMatcherFunc<
+    internal::HasGrandparentMatcher,
+    internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>,
+    internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>>
+    hasGrandparent;
+
 /// Matches AST nodes that have an ancestor that matches the provided
 /// matcher.
 ///
Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,52 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+// Not all systems have #include <compare> to define std::std_ordering
+// required by operator<=>, so recreate minimal version for tests below.
+namespace std {
+
+struct strong_ordering {
+  static const strong_ordering less;
+  static const strong_ordering equal;
+  static const strong_ordering greater;
+  using zero_type = decltype(nullptr);
+
+  friend constexpr bool operator<(const strong_ordering value, zero_type) noexcept {
+    return value.comparison_value < 0;
+  }
+
+  friend constexpr bool operator>(const strong_ordering value, zero_type) noexcept {
+    return value.comparison_value > 0;
+  }
+
+  friend constexpr bool operator>=(const strong_ordering value, zero_type) noexcept {
+    return value.comparison_value >= 0;
+  }
+
+  signed char comparison_value;
+};
+
+inline constexpr strong_ordering strong_ordering::less{-1};
+inline constexpr strong_ordering strong_ordering::equal{0};
+inline constexpr strong_ordering strong_ordering::greater{1};
+
+} // namespace std
+
+class A {
+public:
+  auto operator<=>(const A &other) const = default;
+};
+
+void test_cxx_rewritten_binary_ops() {
+  A a1, a2;
+  bool result;
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 < a2);
+  // CHECK-FIXES: result = (a1 < a2);
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 >= a2);
+  // CHECK-FIXES: result = (a1 >= a2);
+  int *ptr = 0;
+  // CHECK-FIXES: int *ptr = nullptr;
+  result = (a1 > (ptr == 0 ? a1 : a2));
+  // CHECK-FIXES: result = (a1 > (ptr == nullptr ? a1 : a2));
+}
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
@@ -45,6 +45,8 @@
       TK_AsIs,
       castExpr(anyOf(ImplicitCastToNull,
                      explicitCastExpr(hasDescendant(ImplicitCastToNull))),
+               // Skip implicit casts to 0 generated by operator<=> rewrites.
+               unless(hasGrandparent(cxxRewrittenBinaryOperator())),
                unless(hasAncestor(explicitCastExpr())))
           .bind(CastSequence));
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to