Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -15,6 +15,7 @@ MisplacedArrayIndexCheck.cpp NamedParameterCheck.cpp NamespaceCommentCheck.cpp + OperatorsRepresentationCheck.cpp NonConstParameterCheck.cpp ReadabilityTidyModule.cpp RedundantControlFlowCheck.cpp Index: clang-tidy/readability/OperatorsRepresentationCheck.h =================================================================== --- /dev/null +++ clang-tidy/readability/OperatorsRepresentationCheck.h @@ -0,0 +1,35 @@ +//===--- OperatorsRepresentationCheck.h - clang-tidy--------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_OPERATORS_REPRESENTATION_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_OPERATORS_REPRESENTATION_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// Flags alternative tokens for operators, such as 'compl', 'not' and 'or'. +/// +/// 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) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_OPERATORS_REPRESENTATION_H Index: clang-tidy/readability/OperatorsRepresentationCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/OperatorsRepresentationCheck.cpp @@ -0,0 +1,92 @@ +//===--- OperatorsRepresentationCheck.cpp - clang-tidy---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "OperatorsRepresentationCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace readability { + +AST_MATCHER(BinaryOperator, binaryHasAlternativeRepr) { + switch (Node.getOpcode()) { + case BO_NE: + case BO_And: + case BO_Xor: + case BO_Or: + case BO_LAnd: + case BO_LOr: + case BO_AndAssign: + case BO_OrAssign: + case BO_XorAssign: + return true; + default: + return false; + } +} + +AST_MATCHER(UnaryOperator, unaryHasAlternativeRepr) { + switch (Node.getOpcode()) { + case UO_Not: + case UO_LNot: + return true; + default: + return false; + } +} + +void OperatorsRepresentationCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus) + return; + + // We ignore implicit != operators in C++11 range-based for loops. + Finder->addMatcher(binaryOperator(binaryHasAlternativeRepr(), + unless(hasLHS(ignoringImpCasts( + declRefExpr(to(isImplicit())))))) + .bind("binary"), + this); + Finder->addMatcher(unaryOperator(unaryHasAlternativeRepr()).bind("unary"), + this); +} + +void OperatorsRepresentationCheck::check( + const MatchFinder::MatchResult &Result) { + StringRef PrimarySpelling; + SourceLocation OpLoc; + + if (const auto *B = Result.Nodes.getNodeAs("binary")) { + PrimarySpelling = B->getOpcodeStr(); + OpLoc = B->getOperatorLoc(); + } + + if (const auto *U = Result.Nodes.getNodeAs("unary")) { + PrimarySpelling = UnaryOperator::getOpcodeStr(U->getOpcode()); + OpLoc = U->getOperatorLoc(); + } + + auto &SM = *Result.SourceManager; + OpLoc = SM.getSpellingLoc(OpLoc); + + auto TokenRange = CharSourceRange::getTokenRange(OpLoc); + StringRef Spelling = Lexer::getSourceText(TokenRange, SM, getLangOpts()); + + if (PrimarySpelling != Spelling) { + diag(OpLoc, "'%0' is an alternative token spelling; consider using '%1'") + << Spelling << PrimarySpelling + << FixItHint::CreateReplacement(TokenRange, PrimarySpelling); + } +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -24,6 +24,7 @@ #include "MisplacedArrayIndexCheck.h" #include "NamedParameterCheck.h" #include "NonConstParameterCheck.h" +#include "OperatorsRepresentationCheck.h" #include "RedundantControlFlowCheck.h" #include "RedundantDeclarationCheck.h" #include "RedundantFunctionPtrDereferenceCheck.h" @@ -66,6 +67,8 @@ "readability-misleading-indentation"); CheckFactories.registerCheck( "readability-misplaced-array-index"); + CheckFactories.registerCheck( + "readability-operators-representation"); CheckFactories.registerCheck( "readability-redundant-function-ptr-dereference"); CheckFactories.registerCheck( Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -72,6 +72,12 @@ Finds misleading indentation where braces should be introduced or the code should be reformatted. +- New `readability-operators-representation + `_ check + + Flags (and replaces) the alternative tokens for binary and unary operators, + such as ``not`` (for ``!``) and ``or`` (for ``||``). + - Added `ParameterThreshold` to `readability-function-size`. Finds functions that have more then `ParameterThreshold` parameters and emits a warning. Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -145,6 +145,7 @@ readability-misleading-indentation readability-misplaced-array-index readability-named-parameter + readability-operators-representation readability-non-const-parameter readability-redundant-control-flow readability-redundant-declaration Index: docs/clang-tidy/checks/readability-operators-representation.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/readability-operators-representation.rst @@ -0,0 +1,23 @@ +.. title:: clang-tidy - readability-operators-representation + +readability-operators-representation +==================================== + +Flags (and replaces) the alternative tokens for binary and unary operators by +their primary ones for consistency. + +======= =========== +Primary Alternative +======= =========== +``&&`` ``and`` +``&=`` ``and_eq`` +``&`` ``bitand`` +``|`` ``bitor`` +``~`` ``compl`` +``!`` ``not`` +``!=`` ``not_eq`` +``||`` ``or`` +``|=`` ``or_eq`` +``^`` ``xor`` +``^=`` ``xor_eq`` +======= =========== Index: test/clang-tidy/readability-operators-representation.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-operators-representation.cpp @@ -0,0 +1,63 @@ +// RUN: %check_clang_tidy %s readability-operators-representation %t + +void f() { + bool a, b, c; + + c = a and b; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'and' is an alternative token spelling; consider using '&&' [readability-operators-representation] + // CHECK-FIXES: c = a && b; + c and_eq a; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'and_eq' is an alternative + // CHECK-FIXES: c &= a; + c = a bitand b; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'bitand' is an alternative + // CHECK-FIXES: c = a & b; + c = a bitor b; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'bitor' is an alternative + // CHECK-FIXES: c = a | b; + c = compl a; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'compl' is an alternative + // CHECK-FIXES: c = ~ a; + c = not a; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'not' is an alternative + // CHECK-FIXES: c = ! a; + c = a not_eq b; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'not_eq' is an alternative + // CHECK-FIXES: c = a != b; + c = a or b; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'or' is an alternative + // CHECK-FIXES: c = a || b; + c or_eq a; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'or_eq' is an alternative + // CHECK-FIXES: c |= a; + c = a xor b; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'xor' is an alternative + // CHECK-FIXES: c = a ^ b; + c xor_eq a; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'xor_eq' is an alternative + // CHECK-FIXES: c ^= a; + +#define M a xor + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'xor' is an alternative + // CHECK-FIXES: #define M a ^ + c = M b; + + int arr[2]; + for (int i : arr) // OK (Here is an implicit != operator.) + ; + + auto ptr = &c; // OK + auto i = -1; // OK + c = a && b; // OK + c &= a; // OK + c = !a; // OK +} + +struct S { + friend S &operator and(const S &, const S &); +}; + +int g() { + S s1, s2; + S s3 = s1 and s2; // OK +}