5chmidti updated this revision to Diff 441185.
5chmidti added a comment.
rm unused function
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D128861/new/
https://reviews.llvm.org/D128861
Files:
clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
clang-tools-extra/clang-tidy/cppcoreguidelines/SymmetricBinaryOperatorCheck.cpp
clang-tools-extra/clang-tidy/cppcoreguidelines/SymmetricBinaryOperatorCheck.h
clang-tools-extra/docs/ReleaseNotes.rst
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-symmetric-binary-operator.rst
clang-tools-extra/docs/clang-tidy/checks/list.rst
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-symmetric-binary-operator.cpp
Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-symmetric-binary-operator.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-symmetric-binary-operator.cpp
@@ -0,0 +1,481 @@
+// RUN: %check_clang_tidy -std=c++20 %s cppcoreguidelines-symmetric-binary-operator %t
+
+namespace std {
+class string {
+public:
+ friend bool operator!=(const string &, const string &) { return true; }
+ friend bool operator<(const string &, const string &) { return true; }
+};
+template <typename T>
+class vector {
+public:
+ int size() const;
+ const T &operator[](int) const;
+ friend bool operator==(const vector &, const vector &) = default;
+};
+} // namespace std
+
+using size_t = unsigned long long;
+
+namespace test_base {
+struct A {
+ int X;
+ bool operator==(const A &) const = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend bool operator==(const A&, const A&) = default;
+};
+
+struct A2 {
+ int X;
+ bool operator==(const A2 &rhs) const = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend bool operator==(const A2&, const A2&) = default;
+};
+
+struct B {
+ int X;
+ friend bool operator==(const B &, const B &) = default;
+};
+
+template <typename T>
+struct C {
+ int X;
+ bool operator==(const C &) const = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend bool operator==(const C&, const C&) = default;
+};
+
+template <typename T>
+struct D {
+ int X;
+ friend bool operator==(const D &, const D &) = default;
+};
+
+struct E {
+ int X;
+ bool operator==(const E &) const = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend bool operator==(const E&, const E&) = default;
+};
+
+struct F {
+ int X;
+ friend bool operator==(const F &, const F &) = default;
+};
+
+template <typename T>
+struct G {
+ int X;
+ bool operator==(const G &) const = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend bool operator==(const G&, const G&) = default;
+};
+
+template <typename T>
+struct H {
+ int X;
+ friend bool operator==(const H &, const H &) = default;
+};
+} // namespace test_base
+
+namespace test_constexpr {
+struct A {
+ int X;
+ constexpr bool operator==(const A &) const = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend constexpr bool operator==(const A&, const A&) = default;
+};
+
+struct B {
+ int X;
+ friend constexpr bool operator==(const B &, const B &) = default;
+};
+
+template <typename T>
+struct C {
+ int X;
+ constexpr bool operator==(const C &) const = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend constexpr bool operator==(const C&, const C&) = default;
+};
+
+template <typename T>
+struct D {
+ int X;
+ friend constexpr bool operator==(const D &, const D &) = default;
+};
+
+struct E {
+ int X;
+ constexpr bool operator==(const E &) const = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend constexpr bool operator==(const E&, const E&) = default;
+};
+
+struct F {
+ int X;
+ friend constexpr bool operator==(const F &, const F &) = default;
+};
+
+template <typename T>
+struct G {
+ int X;
+ constexpr bool operator==(const G &) const = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend constexpr bool operator==(const G&, const G&) = default;
+};
+
+template <typename T>
+struct H {
+ int X;
+ friend constexpr bool operator==(const H &, const H &) = default;
+};
+} // namespace test_constexpr
+
+namespace test_trailing_return_type {
+struct A {
+ int X;
+ auto operator==(const A &) const -> bool = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend auto operator==(const A&, const A&) -> bool = default;
+};
+
+struct B {
+ int X;
+ friend auto operator==(const B &, const B &) -> bool = default;
+};
+
+template <typename T>
+struct C {
+ int X;
+ auto operator==(const C &) const -> bool = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend auto operator==(const C&, const C&) -> bool = default;
+};
+
+template <typename T>
+struct D {
+ int X;
+ friend auto operator==(const D &, const D &) -> bool = default;
+};
+
+struct E {
+ int X;
+ auto operator==(const E &) const -> bool = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend auto operator==(const E&, const E&) -> bool = default;
+};
+
+struct F {
+ int X;
+ friend auto operator==(const F &, const F &) -> bool = default;
+};
+
+template <typename T>
+struct G {
+ int X;
+ auto operator==(const G &) const -> bool = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend auto operator==(const G&, const G&) -> bool = default;
+};
+
+template <typename T>
+struct H {
+ int X;
+ friend auto operator==(const H &, const H &) -> bool = default;
+};
+} // namespace test_trailing_return_type
+
+namespace non_default {
+struct A {
+ int X;
+ bool operator==(const A &rhs) const {
+ return X == rhs.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+};
+
+template <typename T>
+struct C {
+ int X;
+ bool operator==(const C &rhs) const {
+ return X == rhs.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+};
+} // namespace non_default
+
+namespace non_const {
+struct A {
+ int X;
+ bool operator==(const A &rhs) {
+ return X == rhs.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+};
+
+template <typename T>
+struct C {
+ int X;
+ bool operator==(const C &rhs) {
+ return X == rhs.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+};
+} // namespace non_const
+
+namespace out_of_class_definition {
+struct A {
+ int X;
+ bool operator==(const A &rhs) const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+};
+
+bool A::operator==(const A &rhs) const {
+ return X == rhs.X;
+}
+
+struct B {
+ int X;
+ bool operator==(const B &rhs) const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+};
+
+template <typename T>
+struct C {
+ int X;
+ bool operator==(const C &rhs) const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+};
+
+template <typename T>
+bool C<T>::operator==(const C<T> &rhs) const {
+ return X == rhs.X;
+}
+} // namespace out_of_class_definition
+
+bool out_of_class_definition::B::operator==(const B &rhs) const {
+ return X == rhs.X;
+}
+
+namespace templates_no_match {
+template <typename T>
+struct A {
+ bool operator==(const T &);
+};
+
+struct B {
+ template <typename T>
+ bool operator==(const T &);
+};
+
+template <typename T>
+struct C {
+ template <typename W>
+ bool operator==(const C<W> &);
+ bool operator!=(const C<int> &);
+};
+
+} // namespace templates_no_match
+
+namespace test_base_definition_not_visible {
+struct A {
+ int X;
+ bool operator==(const A &) const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+};
+
+struct A2 {
+ int X;
+ bool operator==(const A2 &rhs) const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+};
+
+struct B {
+ int X;
+ friend bool operator==(const B &, const B &);
+};
+
+template <typename T>
+struct C {
+ int X;
+ bool operator==(const C &) const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+};
+
+template <typename T>
+struct D {
+ int X;
+ friend bool operator==(const D &, const D &);
+};
+
+struct E {
+ int X;
+ bool operator==(const E &) const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+};
+
+struct F {
+ int X;
+ friend bool operator==(const F &, const F &);
+};
+
+template <typename T>
+struct G {
+ int X;
+ bool operator==(const G &) const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+};
+
+template <typename T>
+struct H {
+ int X;
+ friend bool operator==(const H &, const H &);
+};
+} // namespace test_base_definition_not_visible
+
+namespace additional_operators {
+struct A {
+ bool operator<(const A &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ bool operator+(const A &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ bool operator<<(const A &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ bool operator&&(const A &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ bool operator,(const A &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+
+ bool operator<(const int &);
+ bool operator+(const int &);
+ bool operator<<(const int &);
+ bool operator&&(const int &);
+ bool operator,(const int &);
+};
+
+template <typename T>
+struct B {
+ bool operator<(const B &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ bool operator+(const B &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ bool operator<<(const B &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ bool operator&&(const B &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ bool operator,(const B &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+
+ bool operator<(const int &);
+ bool operator+(const int &);
+ bool operator<<(const int &);
+ bool operator&&(const int &);
+ bool operator,(const int &);
+};
+
+} // namespace additional_operators
+
+namespace test_noexcept {
+
+struct A {
+ int X;
+ bool operator==(const A &) const noexcept = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend bool operator==(const A&, const A&) noexcept = default;
+};
+
+struct A2 {
+ int X;
+ bool operator==(const A2 &rhs) const noexcept = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ // CHECK-FIXES: friend bool operator==(const A2&, const A2&) noexcept = default;
+};
+} // namespace test_noexcept
+
+namespace llvm_omp_testcase {
+template <typename T>
+using SetVector = ::std::vector<T>;
+
+enum class ChangeStatus {
+ CHANGED,
+ UNCHANGED,
+};
+
+ChangeStatus operator|(ChangeStatus l, ChangeStatus r);
+ChangeStatus &operator|=(ChangeStatus &l, ChangeStatus r);
+ChangeStatus operator&(ChangeStatus l, ChangeStatus r);
+ChangeStatus &operator&=(ChangeStatus &l, ChangeStatus r);
+
+struct AbstractState {
+ virtual ~AbstractState() = default;
+};
+
+template <typename base_ty, base_ty BestState, base_ty WorstState>
+struct IntegerStateBase : public AbstractState {
+ using base_t = base_ty;
+
+ IntegerStateBase() = default;
+ IntegerStateBase(base_t Assumed) : Assumed(Assumed) {}
+
+ static constexpr base_t getBestState() { return BestState; }
+ static constexpr base_t getBestState(const IntegerStateBase &) {
+ return getBestState();
+ }
+
+ static constexpr base_t getWorstState() { return WorstState; }
+ static constexpr base_t getWorstState(const IntegerStateBase &) {
+ return getWorstState();
+ }
+
+ base_t getKnown() const { return Known; }
+
+ base_t getAssumed() const { return Assumed; }
+
+ bool
+ operator==(const IntegerStateBase<base_t, BestState, WorstState> &R) const {
+ return this->getAssumed() == R.getAssumed() &&
+ this->getKnown() == R.getKnown();
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+
+ bool
+ operator!=(const IntegerStateBase<base_t, BestState, WorstState> &R) const {
+ return !(*this == R);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+
+protected:
+ virtual void handleNewAssumedValue(base_t Value) = 0;
+
+ virtual void handleNewKnownValue(base_t Value) = 0;
+
+ base_t Known = getWorstState();
+
+ base_t Assumed = getBestState();
+};
+
+struct BooleanState : public IntegerStateBase<bool, true, false> {
+ using super = IntegerStateBase<bool, true, false>;
+ using base_t = IntegerStateBase::base_t;
+
+ BooleanState() = default;
+ BooleanState(base_t Assumed) : super(Assumed) {}
+};
+
+template <typename Ty, bool InsertInvalidates = true>
+struct BooleanStateWithSetVector : public BooleanState {
+ bool operator==(const BooleanStateWithSetVector &RHS) const {
+ return BooleanState::operator==(RHS) && Set == RHS.Set;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+ bool operator!=(const BooleanStateWithSetVector &RHS) const {
+ return !(*this == RHS);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: symmetric binary operator should be a friend or free operator function [cppcoreguidelines-symmetric-binary-operator]
+
+private:
+ SetVector<Ty> Set;
+};
+
+} // namespace llvm_omp_testcase
Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -196,6 +196,7 @@
`cppcoreguidelines-pro-type-vararg <cppcoreguidelines/pro-type-vararg.html>`_,
`cppcoreguidelines-slicing <cppcoreguidelines/slicing.html>`_,
`cppcoreguidelines-special-member-functions <cppcoreguidelines/special-member-functions.html>`_,
+ `cppcoreguidelines-symmetric-binary-operator <cppcoreguidelines-symmetric-binary-operator.html>`_, "Yes"
`cppcoreguidelines-virtual-class-destructor <cppcoreguidelines/virtual-class-destructor.html>`_, "Yes"
`darwin-avoid-spinlock <darwin/avoid-spinlock.html>`_,
`darwin-dispatch-once-nonstatic <darwin/dispatch-once-nonstatic.html>`_, "Yes"
Index: clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-symmetric-binary-operator.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-symmetric-binary-operator.rst
@@ -0,0 +1,35 @@
+.. title:: clang-tidy - cppcoreguidelines-symmetric-binary-operator
+
+cppcoreguidelines-symmetric-binary-operator
+===========================================
+
+This check flags all member operators that are symmetric, i.e. operators where
+both sides of the operator are of the same type and are not compound
+assignment operators.
+
+The check is based on `C++ Core Guidelines C.161 <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c161-use-non-member-functions-for-symmetric-operators>`
+
+Given a simple struct with member operators
+(incomplete set of operators, for demonstration purposes only)
+
+.. code-block:: c++
+
+ struct A {
+ int X;
+ // Member-operator that is symmetric, defaulted and a comparison operator
+ bool operator==(const A &) const = default; // Warn + fix
+ A operator+(const A &rhs) const { return A{X + rhs.X}; } // Warn
+ };
+
+the check matches both member operators ``operator==`` and ``operator+`` and
+warns on both occasions that it is a symmetric binary operator and should be a friend or free function.
+Additionally, a fix is created for symmetric comparison operators, ``operator==`` in the example,
+that rewrites the operator to a friend operator function
+
+.. code-block:: c++
+
+ struct A {
+ int X;
+ friend bool operator==(const A &, const A &) = default; // Rewritten operator
+ A operator+(const A &rhs) const { return A{X + rhs.X}; }
+ };
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -132,6 +132,14 @@
Detects confusable Unicode identifiers.
+- New :doc:`cppcoreguidelines-symmetric-binary-operator
+ <clang-tidy/checks/cppcoreguidelines-symmetric-binary-operator>` check.
+
+ Finds operators that are symmetric with respect to the type of their
+ parameters and warns that these operators should be friend or free functions.
+ Generates fixes for symmetric defaulted comparison operators to be
+ changed to friend operator functions.
+
- New :doc:`modernize-macro-to-enum
<clang-tidy/checks/modernize/macro-to-enum>` check.
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/SymmetricBinaryOperatorCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/SymmetricBinaryOperatorCheck.h
@@ -0,0 +1,34 @@
+//===--- SymmetricBinaryOperatorCheck.h - clang-tidy ------------*- C++ -*-===//
+//
+// 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_CPPCOREGUIDELINES_SYMMETRICBINARYOPERATORCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_SYMMETRICBINARYOPERATORCHECK_H
+
+#include "../utils/TransformerClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// Finds operators that are symmetric with respect to the type of their
+/// parameters. Warns that such operators should be friend functions or free
+/// functions. Generates fixes to change defaulted comparison operators to
+/// defaulted friend operators. See also C.161.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-symmetric-binary-operator.html
+class SymmetricBinaryOperatorCheck : public utils::TransformerClangTidyCheck {
+public:
+ SymmetricBinaryOperatorCheck(StringRef Name, ClangTidyContext *Context);
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_SYMMETRICBINARYOPERATORCHECK_H
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/SymmetricBinaryOperatorCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/SymmetricBinaryOperatorCheck.cpp
@@ -0,0 +1,181 @@
+//===--- SymmetricBinaryOperatorCheck.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 "SymmetricBinaryOperatorCheck.h"
+#include "../utils/LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "clang/Tooling/Transformer/RewriteRule.h"
+#include "clang/Tooling/Transformer/Stencil.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+using transformer::applyFirst;
+using transformer::cat;
+using transformer::changeTo;
+using transformer::insertBefore;
+using transformer::makeRule;
+using transformer::name;
+using transformer::node;
+using transformer::noopEdit;
+using transformer::RangeSelector;
+using transformer::remove;
+using transformer::RewriteRule;
+
+bool isPotentialBinaryOperator(OverloadedOperatorKind Kind) {
+ return llvm::is_contained(
+ std::initializer_list<OverloadedOperatorKind>{
+#define OVERLOADED_OPERATOR_true(Name) OO_##Name,
+#define OVERLOADED_OPERATOR_false(Name)
+
+#define OVERLOADED_OPERATOR_IS_ASSIGNMENT_true(Name, Binary)
+#define OVERLOADED_OPERATOR_IS_ASSIGNMENT_false(Name, Binary) \
+ OVERLOADED_OPERATOR_##Binary(Name)
+
+#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
+ OVERLOADED_OPERATOR_IS_ASSIGNMENT_##MemberOnly(Name, Binary)
+#define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemberOnly)
+
+#include "clang/Basic/OperatorKinds.def"
+ },
+ Kind);
+}
+
+bool isComparisonOperator(OverloadedOperatorKind Kind) {
+ return llvm::is_contained(
+ std::initializer_list<OverloadedOperatorKind>{
+ OO_Less,
+ OO_Greater,
+ OO_EqualEqual,
+ OO_ExclaimEqual,
+ OO_LessEqual,
+ OO_GreaterEqual,
+ OO_Spaceship,
+ OO_AmpAmp,
+ OO_PipePipe,
+ OO_Comma,
+ },
+ Kind);
+}
+
+AST_MATCHER(CXXMethodDecl, isPotentialBinaryOperator) {
+ return isPotentialBinaryOperator(Node.getOverloadedOperator());
+}
+
+AST_MATCHER(CXXMethodDecl, isComparisonOperator) {
+ return isComparisonOperator(Node.getOverloadedOperator());
+}
+
+static llvm::Error invalidArgumentError(Twine Message) {
+ return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
+ Message);
+}
+
+static Expected<DynTypedNode> getNode(const BoundNodes &Nodes, StringRef ID) {
+ auto &NodesMap = Nodes.getMap();
+ auto It = NodesMap.find(ID);
+ if (It == NodesMap.end())
+ return invalidArgumentError("ID not bound: " + ID);
+ return It->second;
+}
+
+static RangeSelector constSpec(std::string ID) {
+ return [ID](const MatchFinder::MatchResult &Result)
+ -> Expected<CharSourceRange> {
+ Expected<DynTypedNode> Node = getNode(Result.Nodes, ID);
+
+ if (!Node)
+ return Node.takeError();
+
+ if (const auto *Method = Node->get<CXXMethodDecl>()) {
+ const SourceLocation ParensEndLoc =
+ Method->getFunctionTypeLoc().getParensRange().getEnd();
+
+ const auto GetNextToken = [&](const SourceLocation Loc) {
+ return utils::lexer::findNextTokenSkippingComments(
+ Loc, *Result.SourceManager, Result.Context->getLangOpts());
+ };
+
+ llvm::Optional<Token> OptToken{GetNextToken(ParensEndLoc)};
+
+ const auto IsConstToken = [](Token &Tok) {
+ return Tok.is(tok::TokenKind::kw_const) ||
+ (Tok.is(tok::TokenKind::raw_identifier) &&
+ Tok.getRawIdentifier().equals("const"));
+ };
+
+ for (; OptToken.hasValue() && !IsConstToken(OptToken.getValue()) &&
+ !OptToken.getValue().isOneOf(tok::TokenKind::l_brace,
+ tok::TokenKind::kw_default,
+ tok::TokenKind::semi);
+ OptToken = GetNextToken(OptToken.getValue().getLocation())) {
+ }
+
+ if (OptToken.hasValue() && IsConstToken(OptToken.getValue())) {
+ const auto Token = OptToken.getValue();
+ return CharSourceRange::getCharRange(Token.getLocation(),
+ Token.getEndLoc());
+ }
+ // This error is unreachable within this check. constSpec is only called
+ // on defaulted symmetric binary operators, which are required to be const
+ // specified.
+ return invalidArgumentError(
+ "constSpec invalid argument: member function is not const qualified");
+ };
+ return invalidArgumentError(
+ "constSpec invalid argument: not a CXXMethodDecl");
+ };
+}
+
+static transformer::RewriteRuleWith<std::string> makeRewriteRule() {
+ const auto Parameter =
+ parmVarDecl(hasType(qualType(references(cxxRecordDecl().bind("record")))))
+ .bind("param");
+
+ const auto IsBinaryOperator =
+ cxxMethodDecl(isPotentialBinaryOperator(), hasParameter(0, Parameter));
+
+ // Using hasParent instead of ofClass because we want to match declarations
+ // within the CXXRecord and not an outside definition
+ const auto BaseMatch =
+ cxxMethodDecl(IsBinaryOperator, unless(hasAncestor(functionDecl())),
+ hasParent(cxxRecordDecl(equalsBoundNode("record"))))
+ .bind("op");
+ const auto MatchDefaultedComparisonOperator =
+ cxxMethodDecl(BaseMatch, isDefaulted(), isComparisonOperator());
+
+ const auto AddFriendToFunctionDecl = insertBefore(node("op"), cat("friend "));
+ const auto RemoveConst = remove(constSpec("op"));
+ const auto AddSecondParameterToDeclaration =
+ changeTo(node("param"),
+ cat("const ", name("record"), "&, const ", name("record"), "&"));
+
+ const auto WarningMessage = cat(
+ "symmetric binary operator should be a friend or free operator function");
+
+ return applyFirst(
+ {makeRule(MatchDefaultedComparisonOperator,
+ {AddFriendToFunctionDecl, RemoveConst,
+ AddSecondParameterToDeclaration},
+ WarningMessage),
+ makeRule(BaseMatch, noopEdit(node("op")), WarningMessage)});
+}
+
+SymmetricBinaryOperatorCheck::SymmetricBinaryOperatorCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : TransformerClangTidyCheck(makeRewriteRule(), Name, Context) {}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
@@ -35,6 +35,7 @@
#include "ProTypeVarargCheck.h"
#include "SlicingCheck.h"
#include "SpecialMemberFunctionsCheck.h"
+#include "SymmetricBinaryOperatorCheck.h"
#include "VirtualClassDestructorCheck.h"
namespace clang {
@@ -95,6 +96,8 @@
CheckFactories.registerCheck<SlicingCheck>("cppcoreguidelines-slicing");
CheckFactories.registerCheck<misc::UnconventionalAssignOperatorCheck>(
"cppcoreguidelines-c-copy-assignment-signature");
+ CheckFactories.registerCheck<SymmetricBinaryOperatorCheck>(
+ "cppcoreguidelines-symmetric-binary-operator");
CheckFactories.registerCheck<VirtualClassDestructorCheck>(
"cppcoreguidelines-virtual-class-destructor");
}
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
@@ -26,6 +26,7 @@
ProTypeVarargCheck.cpp
SlicingCheck.cpp
SpecialMemberFunctionsCheck.cpp
+ SymmetricBinaryOperatorCheck.cpp
VirtualClassDestructorCheck.cpp
LINK_LIBS
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits