[clang-tools-extra] a084854 - [clang-tidy] Add readability-operators-representation check
Piotr Zegar via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 31 09:07:27 PDT 2023
Author: Piotr Zegar
Date: 2023-03-31T16:07:16Z
New Revision: a084854266ca60748982228a4c98d036bca5f762
URL: https://github.com/llvm/llvm-project/commit/a084854266ca60748982228a4c98d036bca5f762
DIFF: https://github.com/llvm/llvm-project/commit/a084854266ca60748982228a4c98d036bca5f762.diff
LOG: [clang-tidy] Add readability-operators-representation check
Check helps enforce consistent token representation for binary, unary and
overloaded operators in C++ code. The check supports both traditional and
alternative representations of operators.
Reviewed By: carlosgalvezp
Differential Revision: https://reviews.llvm.org/D144522
Added:
clang-tools-extra/clang-tidy/readability/OperatorsRepresentationCheck.cpp
clang-tools-extra/clang-tidy/readability/OperatorsRepresentationCheck.h
clang-tools-extra/docs/clang-tidy/checks/readability/operators-representation.rst
clang-tools-extra/test/clang-tidy/checkers/readability/operators-representation-to-alternative.cpp
clang-tools-extra/test/clang-tidy/checkers/readability/operators-representation-to-traditional.cpp
Modified:
clang-tools-extra/clang-tidy/readability/CMakeLists.txt
clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
clang-tools-extra/docs/ReleaseNotes.rst
clang-tools-extra/docs/clang-tidy/checks/list.rst
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 2306641ca9215..421698cd615f9 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -29,6 +29,7 @@ add_clang_library(clangTidyReadabilityModule
NamedParameterCheck.cpp
NamespaceCommentCheck.cpp
NonConstParameterCheck.cpp
+ OperatorsRepresentationCheck.cpp
QualifiedAutoCheck.cpp
ReadabilityTidyModule.cpp
RedundantAccessSpecifiersCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/OperatorsRepresentationCheck.cpp b/clang-tools-extra/clang-tidy/readability/OperatorsRepresentationCheck.cpp
new file mode 100644
index 0000000000000..ab45dab71689a
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/OperatorsRepresentationCheck.cpp
@@ -0,0 +1,335 @@
+//===--- OperatorsRepresentationCheck.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 "OperatorsRepresentationCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/STLExtras.h"
+#include <array>
+#include <utility>
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+static StringRef getOperatorSpelling(SourceLocation Loc, ASTContext &Context) {
+ if (Loc.isInvalid())
+ return {};
+
+ SourceManager &SM = Context.getSourceManager();
+
+ Loc = SM.getSpellingLoc(Loc);
+ if (Loc.isInvalid())
+ return {};
+
+ const CharSourceRange TokenRange = CharSourceRange::getTokenRange(Loc);
+ return Lexer::getSourceText(TokenRange, SM, Context.getLangOpts());
+}
+
+namespace {
+
+AST_MATCHER_P2(BinaryOperator, hasInvalidBinaryOperatorRepresentation,
+ BinaryOperatorKind, Kind, llvm::StringRef,
+ ExpectedRepresentation) {
+ if (Node.getOpcode() != Kind || ExpectedRepresentation.empty())
+ return false;
+
+ StringRef Spelling =
+ getOperatorSpelling(Node.getOperatorLoc(), Finder->getASTContext());
+ return !Spelling.empty() && Spelling != ExpectedRepresentation;
+}
+
+AST_MATCHER_P2(UnaryOperator, hasInvalidUnaryOperatorRepresentation,
+ UnaryOperatorKind, Kind, llvm::StringRef,
+ ExpectedRepresentation) {
+ if (Node.getOpcode() != Kind || ExpectedRepresentation.empty())
+ return false;
+
+ StringRef Spelling =
+ getOperatorSpelling(Node.getOperatorLoc(), Finder->getASTContext());
+ return !Spelling.empty() && Spelling != ExpectedRepresentation;
+}
+
+AST_MATCHER_P2(CXXOperatorCallExpr, hasInvalidOverloadedOperatorRepresentation,
+ OverloadedOperatorKind, Kind, llvm::StringRef,
+ ExpectedRepresentation) {
+ if (Node.getOperator() != Kind || ExpectedRepresentation.empty())
+ return false;
+
+ StringRef Spelling =
+ getOperatorSpelling(Node.getOperatorLoc(), Finder->getASTContext());
+ return !Spelling.empty() && Spelling != ExpectedRepresentation;
+}
+
+} // namespace
+
+constexpr std::array<std::pair<llvm::StringRef, llvm::StringRef>, 2U>
+ UnaryRepresentation{{{"!", "not"}, {"~", "compl"}}};
+
+constexpr std::array<std::pair<llvm::StringRef, llvm::StringRef>, 9U>
+ OperatorsRepresentation{{{"&&", "and"},
+ {"||", "or"},
+ {"^", "xor"},
+ {"&", "bitand"},
+ {"|", "bitor"},
+ {"&=", "and_eq"},
+ {"|=", "or_eq"},
+ {"!=", "not_eq"},
+ {"^=", "xor_eq"}}};
+
+static llvm::StringRef translate(llvm::StringRef Value) {
+ for (const auto &[Traditional, Alternative] : UnaryRepresentation) {
+ if (Value == Traditional)
+ return Alternative;
+ if (Value == Alternative)
+ return Traditional;
+ }
+
+ for (const auto &[Traditional, Alternative] : OperatorsRepresentation) {
+ if (Value == Traditional)
+ return Alternative;
+ if (Value == Alternative)
+ return Traditional;
+ }
+ return {};
+}
+
+static bool isNotOperatorStr(llvm::StringRef Value) {
+ return translate(Value).empty();
+}
+
+static bool isSeparator(char C) noexcept {
+ constexpr llvm::StringRef Separators(" \t\r\n\0()<>{};,");
+ return llvm::is_contained(Separators, C);
+}
+
+static bool needEscaping(llvm::StringRef Operator) {
+ switch (Operator[0]) {
+ case '&':
+ case '|':
+ case '!':
+ case '^':
+ case '~':
+ return false;
+ default:
+ return true;
+ }
+}
+
+static llvm::StringRef
+getRepresentation(const std::vector<llvm::StringRef> &Config,
+ llvm::StringRef Traditional, llvm::StringRef Alternative) {
+ if (llvm::is_contained(Config, Traditional))
+ return Traditional;
+ if (llvm::is_contained(Config, Alternative))
+ return Alternative;
+ return {};
+}
+
+template <typename T>
+static bool isAnyOperatorEnabled(const std::vector<llvm::StringRef> &Config,
+ T &&Operators) {
+ for (const auto &[traditional, alternative] : Operators) {
+ if (!getRepresentation(Config, traditional, alternative).empty())
+ return true;
+ }
+ return false;
+}
+
+OperatorsRepresentationCheck::OperatorsRepresentationCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ BinaryOperators(
+ utils::options::parseStringList(Options.get("BinaryOperators", ""))),
+ OverloadedOperators(utils::options::parseStringList(
+ Options.get("OverloadedOperators", ""))) {
+ llvm::erase_if(BinaryOperators, isNotOperatorStr);
+ llvm::erase_if(OverloadedOperators, isNotOperatorStr);
+}
+
+void OperatorsRepresentationCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "BinaryOperators",
+ utils::options::serializeStringList(BinaryOperators));
+ Options.store(Opts, "OverloadedOperators",
+ utils::options::serializeStringList(OverloadedOperators));
+}
+
+std::optional<TraversalKind>
+OperatorsRepresentationCheck::getCheckTraversalKind() const {
+ return TK_IgnoreUnlessSpelledInSource;
+}
+
+bool OperatorsRepresentationCheck::isLanguageVersionSupported(
+ const LangOptions &LangOpts) const {
+ return LangOpts.CPlusPlus;
+}
+
+void OperatorsRepresentationCheck::registerBinaryOperatorMatcher(
+ MatchFinder *Finder) {
+ if (!isAnyOperatorEnabled(BinaryOperators, OperatorsRepresentation))
+ return;
+
+ Finder->addMatcher(
+ binaryOperator(
+ unless(isExpansionInSystemHeader()),
+ anyOf(hasInvalidBinaryOperatorRepresentation(
+ BO_LAnd, getRepresentation(BinaryOperators, "&&", "and")),
+ hasInvalidBinaryOperatorRepresentation(
+ BO_LOr, getRepresentation(BinaryOperators, "||", "or")),
+ hasInvalidBinaryOperatorRepresentation(
+ BO_NE, getRepresentation(BinaryOperators, "!=", "not_eq")),
+ hasInvalidBinaryOperatorRepresentation(
+ BO_Xor, getRepresentation(BinaryOperators, "^", "xor")),
+ hasInvalidBinaryOperatorRepresentation(
+ BO_And, getRepresentation(BinaryOperators, "&", "bitand")),
+ hasInvalidBinaryOperatorRepresentation(
+ BO_Or, getRepresentation(BinaryOperators, "|", "bitor")),
+ hasInvalidBinaryOperatorRepresentation(
+ BO_AndAssign,
+ getRepresentation(BinaryOperators, "&=", "and_eq")),
+ hasInvalidBinaryOperatorRepresentation(
+ BO_OrAssign,
+ getRepresentation(BinaryOperators, "|=", "or_eq")),
+ hasInvalidBinaryOperatorRepresentation(
+ BO_XorAssign,
+ getRepresentation(BinaryOperators, "^=", "xor_eq"))))
+ .bind("binary_op"),
+ this);
+}
+
+void OperatorsRepresentationCheck::registerUnaryOperatorMatcher(
+ MatchFinder *Finder) {
+ if (!isAnyOperatorEnabled(BinaryOperators, UnaryRepresentation))
+ return;
+
+ Finder->addMatcher(
+ unaryOperator(
+ unless(isExpansionInSystemHeader()),
+ anyOf(hasInvalidUnaryOperatorRepresentation(
+ UO_LNot, getRepresentation(BinaryOperators, "!", "not")),
+ hasInvalidUnaryOperatorRepresentation(
+ UO_Not, getRepresentation(BinaryOperators, "~", "compl"))))
+ .bind("unary_op"),
+ this);
+}
+
+void OperatorsRepresentationCheck::registerOverloadedOperatorMatcher(
+ MatchFinder *Finder) {
+ if (!isAnyOperatorEnabled(OverloadedOperators, OperatorsRepresentation) &&
+ !isAnyOperatorEnabled(OverloadedOperators, UnaryRepresentation))
+ return;
+
+ Finder->addMatcher(
+ cxxOperatorCallExpr(
+ unless(isExpansionInSystemHeader()),
+ anyOf(
+ hasInvalidOverloadedOperatorRepresentation(
+ OO_AmpAmp,
+ getRepresentation(OverloadedOperators, "&&", "and")),
+ hasInvalidOverloadedOperatorRepresentation(
+ OO_PipePipe,
+ getRepresentation(OverloadedOperators, "||", "or")),
+ hasInvalidOverloadedOperatorRepresentation(
+ OO_Exclaim,
+ getRepresentation(OverloadedOperators, "!", "not")),
+ hasInvalidOverloadedOperatorRepresentation(
+ OO_ExclaimEqual,
+ getRepresentation(OverloadedOperators, "!=", "not_eq")),
+ hasInvalidOverloadedOperatorRepresentation(
+ OO_Caret, getRepresentation(OverloadedOperators, "^", "xor")),
+ hasInvalidOverloadedOperatorRepresentation(
+ OO_Amp,
+ getRepresentation(OverloadedOperators, "&", "bitand")),
+ hasInvalidOverloadedOperatorRepresentation(
+ OO_Pipe,
+ getRepresentation(OverloadedOperators, "|", "bitor")),
+ hasInvalidOverloadedOperatorRepresentation(
+ OO_AmpEqual,
+ getRepresentation(OverloadedOperators, "&=", "and_eq")),
+ hasInvalidOverloadedOperatorRepresentation(
+ OO_PipeEqual,
+ getRepresentation(OverloadedOperators, "|=", "or_eq")),
+ hasInvalidOverloadedOperatorRepresentation(
+ OO_CaretEqual,
+ getRepresentation(OverloadedOperators, "^=", "xor_eq")),
+ hasInvalidOverloadedOperatorRepresentation(
+ OO_Tilde,
+ getRepresentation(OverloadedOperators, "~", "compl"))))
+ .bind("overloaded_op"),
+ this);
+}
+
+void OperatorsRepresentationCheck::registerMatchers(MatchFinder *Finder) {
+ registerBinaryOperatorMatcher(Finder);
+ registerUnaryOperatorMatcher(Finder);
+ registerOverloadedOperatorMatcher(Finder);
+}
+
+void OperatorsRepresentationCheck::check(
+ const MatchFinder::MatchResult &Result) {
+
+ SourceLocation Loc;
+
+ if (const auto *Op = Result.Nodes.getNodeAs<BinaryOperator>("binary_op"))
+ Loc = Op->getOperatorLoc();
+ else if (const auto *Op = Result.Nodes.getNodeAs<UnaryOperator>("unary_op"))
+ Loc = Op->getOperatorLoc();
+ else if (const auto *Op =
+ Result.Nodes.getNodeAs<CXXOperatorCallExpr>("overloaded_op"))
+ Loc = Op->getOperatorLoc();
+
+ if (Loc.isInvalid())
+ return;
+
+ Loc = Result.SourceManager->getSpellingLoc(Loc);
+ if (Loc.isInvalid() || Loc.isMacroID())
+ return;
+
+ const CharSourceRange TokenRange = CharSourceRange::getTokenRange(Loc);
+ if (TokenRange.isInvalid())
+ return;
+
+ StringRef Spelling = Lexer::getSourceText(TokenRange, *Result.SourceManager,
+ Result.Context->getLangOpts());
+ StringRef TranslatedSpelling = translate(Spelling);
+
+ if (TranslatedSpelling.empty())
+ return;
+
+ std::string FixSpelling = TranslatedSpelling.str();
+
+ StringRef SourceRepresentation = "an alternative";
+ StringRef TargetRepresentation = "a traditional";
+ if (needEscaping(TranslatedSpelling)) {
+ SourceRepresentation = "a traditional";
+ TargetRepresentation = "an alternative";
+
+ StringRef SpellingEx = Lexer::getSourceText(
+ CharSourceRange::getCharRange(
+ TokenRange.getBegin().getLocWithOffset(-1),
+ TokenRange.getBegin().getLocWithOffset(Spelling.size() + 1U)),
+ *Result.SourceManager, Result.Context->getLangOpts());
+ if (SpellingEx.empty() || !isSeparator(SpellingEx.front()))
+ FixSpelling.insert(FixSpelling.begin(), ' ');
+ if (SpellingEx.empty() || !isSeparator(SpellingEx.back()))
+ FixSpelling.push_back(' ');
+ }
+
+ diag(
+ Loc,
+ "'%0' is %1 token spelling, consider using %2 token '%3' for consistency")
+ << Spelling << SourceRepresentation << TargetRepresentation
+ << TranslatedSpelling
+ << FixItHint::CreateReplacement(TokenRange, FixSpelling);
+}
+
+} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/clang-tidy/readability/OperatorsRepresentationCheck.h b/clang-tools-extra/clang-tidy/readability/OperatorsRepresentationCheck.h
new file mode 100644
index 0000000000000..d315f3912a914
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/OperatorsRepresentationCheck.h
@@ -0,0 +1,42 @@
+//===--- OperatorsRepresentationCheck.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_READABILITY_OPERATORSREPRESENTATIONCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_OPERATORSREPRESENTATIONCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include <vector>
+
+namespace clang::tidy::readability {
+
+/// Enforces consistent token representation for invoked binary, unary
+/// and overloaded operators in C++ code.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability/operators-representation.html
+class OperatorsRepresentationCheck : public ClangTidyCheck {
+public:
+ OperatorsRepresentationCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
+ std::optional<TraversalKind> getCheckTraversalKind() const override;
+
+private:
+ void registerBinaryOperatorMatcher(ast_matchers::MatchFinder *Finder);
+ void registerUnaryOperatorMatcher(ast_matchers::MatchFinder *Finder);
+ void registerOverloadedOperatorMatcher(ast_matchers::MatchFinder *Finder);
+
+ std::vector<llvm::StringRef> BinaryOperators;
+ std::vector<llvm::StringRef> OverloadedOperators;
+};
+
+} // namespace clang::tidy::readability
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_OPERATORSREPRESENTATIONCHECK_H
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index 7fd9191844897..f95fa636f1577 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -33,6 +33,7 @@
#include "MisplacedArrayIndexCheck.h"
#include "NamedParameterCheck.h"
#include "NonConstParameterCheck.h"
+#include "OperatorsRepresentationCheck.h"
#include "QualifiedAutoCheck.h"
#include "RedundantAccessSpecifiersCheck.h"
#include "RedundantControlFlowCheck.h"
@@ -103,6 +104,8 @@ class ReadabilityModule : public ClangTidyModule {
"readability-misleading-indentation");
CheckFactories.registerCheck<MisplacedArrayIndexCheck>(
"readability-misplaced-array-index");
+ CheckFactories.registerCheck<OperatorsRepresentationCheck>(
+ "readability-operators-representation");
CheckFactories.registerCheck<QualifiedAutoCheck>(
"readability-qualified-auto");
CheckFactories.registerCheck<RedundantAccessSpecifiersCheck>(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 413f8925aec2c..156e9d73c7be0 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -140,6 +140,12 @@ New checks
directives by analyzing ``#if`` conditions, such as ``#if 0`` and
``#if 1``, etc.
+- New :doc:`readability-operators-representation
+ <clang-tidy/checks/readability/operators-representation>` check.
+
+ Enforces consistent token representation for invoked binary, unary and
+ overloaded operators in C++ code.
+
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 095f32f38da77..44530a09b2479 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -354,6 +354,7 @@ Clang-Tidy Checks
`readability-misplaced-array-index <readability/misplaced-array-index.html>`_, "Yes"
`readability-named-parameter <readability/named-parameter.html>`_, "Yes"
`readability-non-const-parameter <readability/non-const-parameter.html>`_, "Yes"
+ `readability-operators-representation <readability/operators-representation.html>`_, "Yes"
`readability-qualified-auto <readability/qualified-auto.html>`_, "Yes"
`readability-redundant-access-specifiers <readability/redundant-access-specifiers.html>`_, "Yes"
`readability-redundant-control-flow <readability/redundant-control-flow.html>`_, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/operators-representation.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/operators-representation.rst
new file mode 100644
index 0000000000000..b84f7a1c40bd4
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/operators-representation.rst
@@ -0,0 +1,86 @@
+.. title:: clang-tidy - readability-operators-representation
+
+readability-operators-representation
+====================================
+
+Enforces consistent token representation for invoked binary, unary and
+overloaded operators in C++ code. The check supports both traditional and
+alternative representations of operators, such as ``&&`` and ``and``, ``||``
+and ``or``, and so on.
+
+In the realm of C++ programming, developers have the option to choose between
+two distinct representations for operators: traditional token representation
+and alternative token representation. Traditional tokens utilize symbols,
+such as ``&&``, ``||``, and ``!``, while alternative tokens employ more
+descriptive words like ``and``, ``or``, and ``not``.
+
+In the following mapping table, a comprehensive list of traditional and
+alternative tokens, along with their corresponding representations,
+is presented:
+
+.. table:: Token Representation Mapping Table
+ :widths: auto
+
+ =========== ===========
+ Traditional Alternative
+ =========== ===========
+ ``&&`` ``and``
+ ``&=`` ``and_eq``
+ ``&`` ``bitand``
+ ``|`` ``bitor``
+ ``~`` ``compl``
+ ``!`` ``not``
+ ``!=`` ``not_eq``
+ ``||`` ``or``
+ ``|=`` ``or_eq``
+ ``^`` ``xor``
+ ``^=`` ``xor_eq``
+ =========== ===========
+
+Example
+-------
+
+.. code-block:: c++
+
+ // Traditional Token Representation:
+
+ if (!a||!b)
+ {
+ // do something
+ }
+
+ // Alternative Token Representation:
+
+ if (not a or not b)
+ {
+ // do something
+ }
+
+Options
+-------
+
+Due to the distinct benefits and drawbacks of each representation, the default
+configuration doesn't enforce either. Explicit configuration is needed.
+
+To configure check to enforce Traditional Token Representation for all
+operators set options to `&&;&=;&;|;~;!;!=;||;|=;^;^=`.
+
+To configure check to enforce Alternative Token Representation for all
+operators set options to
+`and;and_eq;bitand;bitor;compl;not;not_eq;or;or_eq;xor;xor_eq`.
+
+Developers do not need to enforce all operators, and can mix the representations
+as desired by specifying a semicolon-separated list of both traditional and
+alternative tokens in the configuration, such as `and;||;not`.
+
+.. option:: BinaryOperators
+
+ This option allows you to specify a semicolon-separated list of binary
+ operators for which you want to enforce specific token representation.
+ The default value is empty string.
+
+.. option:: OverloadedOperators
+
+ This option allows you to specify a semicolon-separated list of overloaded
+ operators for which you want to enforce specific token representation.
+ The default value is empty string.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/operators-representation-to-alternative.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/operators-representation-to-alternative.cpp
new file mode 100644
index 0000000000000..ebaa30dbe29c2
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/operators-representation-to-alternative.cpp
@@ -0,0 +1,177 @@
+// RUN: %check_clang_tidy %s readability-operators-representation %t -- -config="{CheckOptions: [\
+// RUN: {key: readability-operators-representation.BinaryOperators, value: 'and;and_eq;bitand;bitor;compl;not;not_eq;or;or_eq;xor;xor_eq'}, \
+// RUN: {key: readability-operators-representation.OverloadedOperators, value: 'and;and_eq;bitand;bitor;compl;not;not_eq;or;or_eq;xor;xor_eq'}]}" --
+
+void testAllTokensToAlternative(int a, int b) {
+ int value = 0;
+
+ value = a||b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: '||' is a traditional token spelling, consider using an alternative token 'or' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a or b;{{$}}
+
+ value = a&&b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: '&&' is a traditional token spelling, consider using an alternative token 'and' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a and b;{{$}}
+
+ value = a | b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: '|' is a traditional token spelling, consider using an alternative token 'bitor' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a bitor b;{{$}}
+
+ value = a & b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: '&' is a traditional token spelling, consider using an alternative token 'bitand' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a bitand b;{{$}}
+
+ value = !a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: '!' is a traditional token spelling, consider using an alternative token 'not' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = not a;{{$}}
+
+ value = a^b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: '^' is a traditional token spelling, consider using an alternative token 'xor' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a xor b;{{$}}
+
+ value = ~b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: '~' is a traditional token spelling, consider using an alternative token 'compl' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = compl b;{{$}}
+
+ value &= b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: '&=' is a traditional token spelling, consider using an alternative token 'and_eq' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value and_eq b;{{$}}
+
+ value |= b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: '|=' is a traditional token spelling, consider using an alternative token 'or_eq' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value or_eq b;{{$}}
+
+ value = a != b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: '!=' is a traditional token spelling, consider using an alternative token 'not_eq' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a not_eq b;{{$}}
+
+ value ^= a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: '^=' is a traditional token spelling, consider using an alternative token 'xor_eq' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value xor_eq a;{{$}}
+}
+
+struct Class {
+ bool operator!() const;
+ Class operator~() const;
+ bool operator&&(const Class&) const;
+ Class operator&(const Class&) const;
+ bool operator||(const Class&) const;
+ Class operator|(const Class&) const;
+ Class operator^(const Class&) const;
+ Class& operator&=(const Class&) const;
+ Class& operator|=(const Class&) const;
+ Class& operator^=(const Class&) const;
+ bool operator!=(const Class&) const;
+};
+
+void testAllTokensToAlternative(Class a, Class b) {
+ int value = 0;
+ Class clval;
+
+ value = a||b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: '||' is a traditional token spelling, consider using an alternative token 'or' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a or b;{{$}}
+
+ value = a&&b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: '&&' is a traditional token spelling, consider using an alternative token 'and' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a and b;{{$}}
+
+ clval = a | b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: '|' is a traditional token spelling, consider using an alternative token 'bitor' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = a bitor b;{{$}}
+
+ clval = a & b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: '&' is a traditional token spelling, consider using an alternative token 'bitand' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = a bitand b;{{$}}
+
+ value = !a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: '!' is a traditional token spelling, consider using an alternative token 'not' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = not a;{{$}}
+
+ clval = a^b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: '^' is a traditional token spelling, consider using an alternative token 'xor' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = a xor b;{{$}}
+
+ clval = ~b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: '~' is a traditional token spelling, consider using an alternative token 'compl' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = compl b;{{$}}
+
+ clval &= b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: '&=' is a traditional token spelling, consider using an alternative token 'and_eq' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval and_eq b;{{$}}
+
+ clval |= b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: '|=' is a traditional token spelling, consider using an alternative token 'or_eq' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval or_eq b;{{$}}
+
+ value = a != b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: '!=' is a traditional token spelling, consider using an alternative token 'not_eq' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a not_eq b;{{$}}
+
+ clval ^= a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: '^=' is a traditional token spelling, consider using an alternative token 'xor_eq' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval xor_eq a;{{$}}
+}
+
+struct ClassO {};
+
+ClassO& operator&=(ClassO&, const ClassO&);
+ClassO& operator|=(ClassO&, const ClassO&);
+ClassO& operator^=(ClassO&, const ClassO&);
+bool operator!=(const ClassO&, const ClassO&);
+bool operator&&(const ClassO&, const ClassO&);
+bool operator||(const ClassO&, const ClassO&);
+bool operator!(const ClassO&);
+ClassO operator&(const ClassO&, const ClassO&);
+ClassO operator|(const ClassO&, const ClassO&);
+ClassO operator^(const ClassO&, const ClassO&);
+ClassO operator~(const ClassO&);
+
+void testAllTokensToAlternative(ClassO a, ClassO b) {
+ int value = 0;
+ ClassO clval;
+
+ value = a||b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: '||' is a traditional token spelling, consider using an alternative token 'or' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a or b;{{$}}
+
+ value = a&&b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: '&&' is a traditional token spelling, consider using an alternative token 'and' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a and b;{{$}}
+
+ clval = a | b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: '|' is a traditional token spelling, consider using an alternative token 'bitor' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = a bitor b;{{$}}
+
+ clval = a & b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: '&' is a traditional token spelling, consider using an alternative token 'bitand' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = a bitand b;{{$}}
+
+ value = !a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: '!' is a traditional token spelling, consider using an alternative token 'not' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = not a;{{$}}
+
+ clval = a^b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: '^' is a traditional token spelling, consider using an alternative token 'xor' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = a xor b;{{$}}
+
+ clval = ~b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: '~' is a traditional token spelling, consider using an alternative token 'compl' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = compl b;{{$}}
+
+ clval &= b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: '&=' is a traditional token spelling, consider using an alternative token 'and_eq' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval and_eq b;{{$}}
+
+ clval |= b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: '|=' is a traditional token spelling, consider using an alternative token 'or_eq' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval or_eq b;{{$}}
+
+ value = a != b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: '!=' is a traditional token spelling, consider using an alternative token 'not_eq' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a not_eq b;{{$}}
+
+ clval ^= a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: '^=' is a traditional token spelling, consider using an alternative token 'xor_eq' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval xor_eq a;{{$}}
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/operators-representation-to-traditional.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/operators-representation-to-traditional.cpp
new file mode 100644
index 0000000000000..e1e47dbf2268f
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/operators-representation-to-traditional.cpp
@@ -0,0 +1,177 @@
+// RUN: %check_clang_tidy %s readability-operators-representation %t -- -config="{CheckOptions: [\
+// RUN: {key: readability-operators-representation.BinaryOperators, value: '&&;&=;&;|;~;!;!=;||;|=;^;^='}, \
+// RUN: {key: readability-operators-representation.OverloadedOperators, value: '&&;&=;&;|;~;!;!=;||;|=;^;^='}]}" --
+
+void testAllTokensToAlternative(int a, int b) {
+ int value = 0;
+
+ value = a or b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'or' is an alternative token spelling, consider using a traditional token '||' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a || b;{{$}}
+
+ value = a and b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'and' is an alternative token spelling, consider using a traditional token '&&' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a && b;{{$}}
+
+ value = a bitor b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'bitor' is an alternative token spelling, consider using a traditional token '|' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a | b;{{$}}
+
+ value = a bitand b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'bitand' is an alternative token spelling, consider using a traditional token '&' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a & b;{{$}}
+
+ value = not a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: 'not' is an alternative token spelling, consider using a traditional token '!' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = ! a;{{$}}
+
+ value = a xor b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'xor' is an alternative token spelling, consider using a traditional token '^' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a ^ b;{{$}}
+
+ value = compl b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: 'compl' is an alternative token spelling, consider using a traditional token '~' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = ~ b;{{$}}
+
+ value and_eq b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'and_eq' is an alternative token spelling, consider using a traditional token '&=' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value &= b;{{$}}
+
+ value or_eq b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'or_eq' is an alternative token spelling, consider using a traditional token '|=' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value |= b;{{$}}
+
+ value = a not_eq b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'not_eq' is an alternative token spelling, consider using a traditional token '!=' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a != b;{{$}}
+
+ value xor_eq a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'xor_eq' is an alternative token spelling, consider using a traditional token '^=' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value ^= a;{{$}}
+}
+
+struct Class {
+ bool operator!() const;
+ Class operator~() const;
+ bool operator&&(const Class&) const;
+ Class operator&(const Class&) const;
+ bool operator||(const Class&) const;
+ Class operator|(const Class&) const;
+ Class operator^(const Class&) const;
+ Class& operator&=(const Class&) const;
+ Class& operator|=(const Class&) const;
+ Class& operator^=(const Class&) const;
+ bool operator!=(const Class&) const;
+};
+
+void testAllTokensToAlternative(Class a, Class b) {
+ int value = 0;
+ Class clval;
+
+ value = a or b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'or' is an alternative token spelling, consider using a traditional token '||' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a || b;{{$}}
+
+ value = a and b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'and' is an alternative token spelling, consider using a traditional token '&&' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a && b;{{$}}
+
+ clval = a bitor b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'bitor' is an alternative token spelling, consider using a traditional token '|' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = a | b;{{$}}
+
+ clval = a bitand b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'bitand' is an alternative token spelling, consider using a traditional token '&' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = a & b;{{$}}
+
+ value = not a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: 'not' is an alternative token spelling, consider using a traditional token '!' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = ! a;{{$}}
+
+ clval = a xor b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'xor' is an alternative token spelling, consider using a traditional token '^' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = a ^ b;{{$}}
+
+ clval = compl b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: 'compl' is an alternative token spelling, consider using a traditional token '~' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = ~ b;{{$}}
+
+ clval and_eq b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'and_eq' is an alternative token spelling, consider using a traditional token '&=' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval &= b;{{$}}
+
+ clval or_eq b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'or_eq' is an alternative token spelling, consider using a traditional token '|=' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval |= b;{{$}}
+
+ value = a not_eq b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'not_eq' is an alternative token spelling, consider using a traditional token '!=' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a != b;{{$}}
+
+ clval xor_eq a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'xor_eq' is an alternative token spelling, consider using a traditional token '^=' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval ^= a;{{$}}
+}
+
+struct ClassO {};
+
+ClassO& operator&=(ClassO&, const ClassO&);
+ClassO& operator|=(ClassO&, const ClassO&);
+ClassO& operator^=(ClassO&, const ClassO&);
+bool operator!=(const ClassO&, const ClassO&);
+bool operator&&(const ClassO&, const ClassO&);
+bool operator||(const ClassO&, const ClassO&);
+bool operator!(const ClassO&);
+ClassO operator&(const ClassO&, const ClassO&);
+ClassO operator|(const ClassO&, const ClassO&);
+ClassO operator^(const ClassO&, const ClassO&);
+ClassO operator~(const ClassO&);
+
+void testAllTokensToAlternative(ClassO a, ClassO b) {
+ int value = 0;
+ ClassO clval;
+
+ value = a or b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'or' is an alternative token spelling, consider using a traditional token '||' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a || b;{{$}}
+
+ value = a and b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'and' is an alternative token spelling, consider using a traditional token '&&' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a && b;{{$}}
+
+ clval = a bitor b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'bitor' is an alternative token spelling, consider using a traditional token '|' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = a | b;{{$}}
+
+ clval = a bitand b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'bitand' is an alternative token spelling, consider using a traditional token '&' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = a & b;{{$}}
+
+ value = not a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: 'not' is an alternative token spelling, consider using a traditional token '!' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = ! a;{{$}}
+
+ clval = a xor b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'xor' is an alternative token spelling, consider using a traditional token '^' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = a ^ b;{{$}}
+
+ clval = compl b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: 'compl' is an alternative token spelling, consider using a traditional token '~' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval = ~ b;{{$}}
+
+ clval and_eq b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'and_eq' is an alternative token spelling, consider using a traditional token '&=' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval &= b;{{$}}
+
+ clval or_eq b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'or_eq' is an alternative token spelling, consider using a traditional token '|=' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval |= b;{{$}}
+
+ value = a not_eq b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'not_eq' is an alternative token spelling, consider using a traditional token '!=' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}value = a != b;{{$}}
+
+ clval xor_eq a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'xor_eq' is an alternative token spelling, consider using a traditional token '^=' for consistency [readability-operators-representation]
+ // CHECK-FIXES: {{^ }}clval ^= a;{{$}}
+}
More information about the cfe-commits
mailing list