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