diff --git a/clang-tools-extra/clang-tidy/readability/AlternativeTokensCheck.h b/clang-tools-extra/clang-tidy/readability/AlternativeTokensCheck.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/AlternativeTokensCheck.h @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// 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_ALTERNATIVETOKENSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ALTERNATIVETOKENSCHECK_H + +#include "../ClangTidyCheck.h" +#include "../utils/IncludeInserter.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" + +namespace clang { +namespace tidy { +namespace readability { +/// Finds uses of symbol-based logical and bitwise operators and recommends +/// using alternative tokens instead. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability-alternative-tokens.html +class AlternativeTokensCheck : public ClangTidyCheck { +public: + using ClangTidyCheck::ClangTidyCheck; + + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.C99 || LangOpts.CPlusPlus; + } + + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override { + // TODO: add support for checking preprocessor directives + Includer.registerPreprocessor(PP); + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + utils::IncludeInserter Includer{ + Options.getLocalOrGlobal("IncludeStyle", utils::IncludeSorter::IS_LLVM)}; + + void checkSpelling(const SourceManager &SM, const UnaryOperator &Op); + void checkSpelling(const SourceManager &SM, const BinaryOperator &Op); + void checkSpelling(const SourceManager &SM, const CXXOperatorCallExpr &Op); + + Optional includeIso646(const SourceManager &SM, + SourceLocation Loc); + FixItHint createReplacement(const SourceManager &SM, SourceLocation Loc, + StringRef S, int CharLookahead) const; + char lookahead(const SourceManager &SM, SourceLocation Loc, + int CharLookahead) const; +}; +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ALTERNATIVETOKENSCHECK_H diff --git a/clang-tools-extra/clang-tidy/readability/AlternativeTokensCheck.cpp b/clang-tools-extra/clang-tidy/readability/AlternativeTokensCheck.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/AlternativeTokensCheck.cpp @@ -0,0 +1,215 @@ +//===----------------------------------------------------------------------===// +// +// 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 "AlternativeTokensCheck.h" +#include "../utils/IncludeInserter.h" +#include "../utils/LexerUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" + +#include + +namespace clang { +namespace tidy { +namespace readability { +namespace { +AST_MATCHER(UnaryOperator, isBitwiseOrLogicalUnaryOp) { + return Node.getOpcode() == UnaryOperator::Opcode::UO_Not || + Node.getOpcode() == UnaryOperator::Opcode::UO_LNot; +} +} // namespace + +using ast_matchers::binaryOperation; +using ast_matchers::hasAnyOperatorName; +using ast_matchers::MatchFinder; +using ast_matchers::unaryOperator; + +void AlternativeTokensCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(unaryOperator(isBitwiseOrLogicalUnaryOp()).bind("unary"), + this); + Finder->addMatcher( + binaryOperation(hasAnyOperatorName("&&", "||", "!", "&", "|", "~", "^")) + .bind("operator"), + this); +} + +Optional +AlternativeTokensCheck::includeIso646(const SourceManager &SM, + SourceLocation Loc) { + if (!getLangOpts().C99) { + return llvm::None; + } + + return Includer.createIncludeInsertion(SM.getFileID(Loc), ""); +} + +char AlternativeTokensCheck::lookahead(const SourceManager &SM, + SourceLocation Loc, + int CharLookahead) const { + return *(SM.getCharacterData(Loc.getLocWithOffset(CharLookahead))); +} + +FixItHint AlternativeTokensCheck::createReplacement(const SourceManager &SM, + SourceLocation Loc, + StringRef S, + int CharLookahead) const { + // Only insert spaces if there aren't already spaces between operators + StringRef SpaceBefore = std::isspace(lookahead(SM, Loc, -1)) ? "" : " "; + StringRef SpaceAfter = + std::isspace(lookahead(SM, Loc, CharLookahead)) ? "" : " "; + return FixItHint::CreateReplacement(Loc, + (SpaceBefore + S + SpaceAfter).str()); +} + +void AlternativeTokensCheck::checkSpelling(const SourceManager &SM, + const UnaryOperator &Op) { + // TODO: make check configurable so users can decide which operators are to be + // symbols and which are to be words. + + SourceLocation Loc = Op.getOperatorLoc(); + assert(Loc.isValid()); + const char *First = SM.getCharacterData(Loc); + assert(First != nullptr); + if (std::isalpha(*First) || Loc.isMacroID()) + return; + + switch (Op.getOpcode()) { + case UnaryOperator::Opcode::UO_Not: + diag(Loc, "use 'compl' for bitwise negation") + << createReplacement(SM, Loc, "compl", 1) << includeIso646(SM, Loc); + return; + case UnaryOperator::Opcode::UO_LNot: + diag(Loc, "use 'not' for logical negation") + << createReplacement(SM, Loc, "not", 1) << includeIso646(SM, Loc); + return; + default: + return; + } +} + +void AlternativeTokensCheck::checkSpelling(const SourceManager &SM, + const BinaryOperator &Op) { + // TODO: make check configurable so users can decide which operators are to be + // symbols and which are to be words. + + SourceLocation Loc = Op.getOperatorLoc(); + assert(Loc.isValid()); + const char *First = SM.getCharacterData(Loc); + assert(First != nullptr); + if (std::isalpha(*First) || Loc.isMacroID()) + return; + + using Opcode = BinaryOperator::Opcode; + Opcode OC = Op.getOpcode(); + switch (OC) { + case Opcode::BO_LAnd: + diag(Loc, "use 'and' for logical conjunctions") + << createReplacement(SM, Loc, "and", 2) << includeIso646(SM, Loc); + break; + case Opcode::BO_And: + diag(Loc, "use 'bitand' for bitwise conjunctions") + << createReplacement(SM, Loc, "bitand", 1) << includeIso646(SM, Loc); + break; + case Opcode::BO_Or: + diag(Loc, "use 'bitor' for bitwise disjunctions") + << createReplacement(SM, Loc, "bitor", 1) << includeIso646(SM, Loc); + break; + case Opcode::BO_LOr: + diag(Loc, "use 'or' for logical disjunctions") + << createReplacement(SM, Loc, "or", 2) << includeIso646(SM, Loc); + break; + case Opcode::BO_Xor: + diag(Loc, "use 'xor' for exclusive or") + << createReplacement(SM, Loc, "xor", 1) << includeIso646(SM, Loc); + break; + default: + break; + } +} + +void AlternativeTokensCheck::checkSpelling(const SourceManager &SM, + const CXXOperatorCallExpr &Op) { + // TODO: make check configurable so users can decide which operators are to be + // symbols and which are to be words. + + // TODO: add check to make it possible to "intelligently" determine if symbol + // is always preferred (e.g. operator| being used for composition). + + SourceLocation Loc = Op.getOperatorLoc(); + assert(Loc.isValid()); + const char *First = SM.getCharacterData(Loc); + assert(First != nullptr); + if (std::isalpha(*First) || Loc.isMacroID()) + return; + + using Opcode = OverloadedOperatorKind; + constexpr Opcode And = Opcode::OO_AmpAmp; + constexpr Opcode Bitand = Opcode::OO_Amp; + constexpr Opcode Bitor = Opcode::OO_Pipe; + constexpr Opcode Compl = Opcode::OO_Tilde; + constexpr Opcode Not = Opcode::OO_Exclaim; + constexpr Opcode Or = Opcode::OO_PipePipe; + constexpr Opcode Xor = Opcode::OO_Caret; + + Opcode OC = Op.getOperator(); + switch (OC) { + case And: + diag(Loc, "use 'and' for logical conjunctions") + << createReplacement(SM, Loc, "and", 2) << includeIso646(SM, Loc); + break; + case Bitand: + diag(Loc, "use 'bitand' for bitwise conjunctions") + << createReplacement(SM, Loc, "bitand", 1) << includeIso646(SM, Loc); + break; + case Bitor: + diag(Loc, "use 'bitor' for bitwise disjunctions") + << createReplacement(SM, Loc, "bitor", 1) << includeIso646(SM, Loc); + break; + case Compl: + diag(Loc, "use 'compl' for bitwise negation") + << createReplacement(SM, Loc, "compl", 1) << includeIso646(SM, Loc); + break; + case Not: + diag(Loc, "use 'not' for logical negation") + << createReplacement(SM, Loc, "not", 1) << includeIso646(SM, Loc); + break; + case Or: + diag(Loc, "use 'or' for logical disjunctions") + << createReplacement(SM, Loc, "or", 2) << includeIso646(SM, Loc); + break; + case Xor: + diag(Loc, "use 'xor' for exclusive or") + << createReplacement(SM, Loc, "xor", 1) << includeIso646(SM, Loc); + break; + default: + break; + } +} + +void AlternativeTokensCheck::check(const MatchFinder::MatchResult &Result) { + assert(Result.SourceManager != nullptr); + + if (const auto *Op = Result.Nodes.getNodeAs("unary")) + return checkSpelling(*Result.SourceManager, *Op); + + if (const auto *Op = Result.Nodes.getNodeAs("operator")) + return checkSpelling(*Result.SourceManager, *Op); + + if (const auto *Op = Result.Nodes.getNodeAs("operator")) + return checkSpelling(*Result.SourceManager, *Op); +} +} // namespace readability +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt @@ -4,6 +4,7 @@ ) add_clang_library(clangTidyReadabilityModule + AlternativeTokensCheck.cpp AvoidConstParamsInDecls.cpp BracesAroundStatementsCheck.cpp ConstReturnTypeCheck.cpp diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp --- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -9,6 +9,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "AlternativeTokensCheck.h" #include "AvoidConstParamsInDecls.h" #include "BracesAroundStatementsCheck.h" #include "ConstReturnTypeCheck.h" @@ -55,6 +56,8 @@ class ReadabilityModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "readability-alternative-tokens"); CheckFactories.registerCheck( "readability-avoid-const-params-in-decls"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/readability/StrictConstCorrectness.h b/clang-tools-extra/clang-tidy/readability/StrictConstCorrectness.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/StrictConstCorrectness.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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_STRICTCONSTCORRECTNESS_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRICTCONSTCORRECTNESS_H + +#include "../ClangTidyCheck.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +namespace clang { +namespace tidy { +namespace readability { +/// This check identifies when an object, reference, or pointee can be +// const-qualifed. +class StrictConstCorrectness : public ClangTidyCheck { +public: + using ClangTidyCheck::ClangTidyCheck; + + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + + 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_STRICTCONSTCORRECTNESS_H diff --git a/clang-tools-extra/clang-tidy/readability/StrictConstCorrectness.kpp b/clang-tools-extra/clang-tidy/readability/StrictConstCorrectness.kpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/StrictConstCorrectness.kpp @@ -0,0 +1,25 @@ +//===-- StringCompareCheck.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 "StrictConstCorrectness.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +namespace clang { +namespace tidy { +namespace readability { + +using ast_matchers::MatchFinder; + +void StrictConstCorrectness::registerMatchers(MatchFinder *Finder) +{} + +void StrictConstCorrectness::check(const MatchFinder::MatchResult &Result) +{} +} // namespace readability +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability-alternative-tokens.rst b/clang-tools-extra/docs/clang-tidy/checks/readability-alternative-tokens.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/readability-alternative-tokens.rst @@ -0,0 +1,86 @@ +.. title:: clang-tidy - readability-alternative-tokens + +readability-alternative-tokens +================================== + +Finds uses of symbol-based logical and bitwise operators and recommends using +alternative tokens instead. + +Although symbols are the mainstream tokens in syntaxes derived from C, spelling +out the operators can be clearer. It more clearly expresses programmer intention +by reducing barriers for interpretation, makes small operators stand out, makes +similar tokens more visibly distinguishable, and reduces the chances for typos. + +.. code-block:: c++ + + // warning: use 'and' for logical conjunctions + x && y + + // warning: use 'bitand' for bitwise conjunctions + x & y + + // warning: use 'bitor' for bitwise disjunctions + x | y + + // warning: use 'compl' for bitwise negation + ~x + + // warning: use 'not' for logical negation + not x + + // warning: use 'or' for logical disjunctions + x || y + + // warning: use 'xor' for exclusive or + x ^ y + +Supported languages +=================== + +* C99 and later +* C++98 and later + +Limitations +=========== + +The following limitations are planned to be fixed within a reasonable timeframe. + +Configurability +--------------- + +A later variant of this patch will support being able to configure how logical +and bitwise operators are spelt. + +Preprocessor support +-------------------- + +This does not currently support the preprocessor. + +Program composition +------------------- + +This check doesn't yet account for program composition. This means that the +warning is currently in conflict with piping C++20 ranges, as well as any other +library that uses ``|`` as a composition operator. + +.. code-block:: c++ + + // warning: use 'bitor' for bitwise disjunctions + auto evens = std::views::iota(0, 1'000) + | std::views::filter([](int const x) { return x % 2 == 0; }); + + // warning: use 'bitor' for bitwise disjunctions + auto value = qi::int_ | qi::bool_; + + // warning: use 'bitor' for bitwise disjunctions + std::fstream file("hello.txt", std::ios::in | std::ios::out); + +The reason for this limitation is because it's not yet clear how to specify to +clang-tidy that an ``|`` is being used for composition over a genuine bitwise +disjunction. Two ideas under consideration are: + +1. Have implementers apply an attribute such as ``[[clang::composable]]`` which + signals to the linter that ``|`` is preferred. + +2. Have clang-tidy users supply a list of types that can be considered as + composable. diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens-no-warn.c b/clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens-no-warn.c new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens-no-warn.c @@ -0,0 +1,26 @@ +// RUN: %check_clang_tidy %s readability-alternative-tokens %t + +// A note to the reader: the whitespace in this file is important: `1&&0` +// is lexically three tokens, but `1and0` is lexed as a single +// identifier. This test needs to make sure that the fixit applies whitespace in +// its change. + +#include + +// clang-format off + +void f1() +{ + (void)(1 and 0); + (void)(0 bitand 1); + (void)(0 bitor 1); + (void)(compl 0); + (void)(not 0); + (void)(1 or 0); + (void)(0 xor 1); + + // This is here because clang-tidy tests seemingly need at least on CHECK-MESSAGES. + (void)(0 && 1); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'and' for logical conjunctions + // CHECK-FIXES: 0 and 1 +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens.c b/clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens.c new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens.c @@ -0,0 +1,122 @@ +// RUN: %check_clang_tidy %s readability-alternative-tokens %t + +// A note to the reader: the whitespace in this file is important: `1&&0` +// is lexically three tokens, but `1and0` is lexed as a single +// identifier. This test needs to make sure that the fixit applies whitespace in +// its change. + +// CHECK-FIXES: #include + +// clang-format off + +void logical_and() +{ + (void)(1&&0); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'and' for logical conjunctions + // CHECK-FIXES: 1 and 0 + + (void)(1&& 0); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'and' for logical conjunctions + // CHECK-FIXES: 1 and 0 + + (void)(1 &&0); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'and' for logical conjunctions + // CHECK-FIXES: 1 and 0 + + (void)(1 && 0); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'and' for logical conjunctions + // CHECK-FIXES: 1 and 0 +} + +void bitwise_and() +{ + (void)(0&1); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitand' for bitwise conjunctions + // CHECK-FIXES: 0 bitand 1 + + (void)(0 &1); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitand' for bitwise conjunctions + // CHECK-FIXES: 0 bitand 1 + + (void)(0& 1); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitand' for bitwise conjunctions + // CHECK-FIXES: 0 bitand 1 + + (void)(0 & 1); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitand' for bitwise conjunctions + // CHECK-FIXES: 0 bitand 1 +} + +void bitwise_or() { + (void)(0|1); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitor' for bitwise disjunctions + // CHECK-FIXES: 0 bitor 1 + + (void)(0| 1); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitor' for bitwise disjunctions + // CHECK-FIXES: 0 bitor 1 + + (void)(0 |1); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitor' for bitwise disjunctions + // CHECK-FIXES: 0 bitor 1 + + (void)(0 | 1); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitor' for bitwise disjunctions + // CHECK-FIXES: 0 bitor 1 +} + +void bitwise_not() { + (void)(~0); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'compl' for bitwise negation + // CHECK-FIXES: compl 0 + + (void)(~ 0); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'compl' for bitwise negation + // CHECK-FIXES: compl 0 +} + +void logical_not() { + (void)(!0); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'not' for logical negation + // CHECK-FIXES: not 0 + + (void)(! 0); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'not' for logical negation + // CHECK-FIXES: not 0 +} + +void logical_or() { + (void)(1||0); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'or' for logical disjunctions + // CHECK-FIXES: 1 or 0 + + (void)(1|| 0); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'or' for logical disjunctions + // CHECK-FIXES: 1 or 0 + + (void)(1 ||0); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'or' for logical disjunctions + // CHECK-FIXES: 1 or 0 + + (void)(1 || 0); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'or' for logical disjunctions + // CHECK-FIXES: 1 or 0 +} + +void bitwise_xor() { + (void)(0^1); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'xor' for exclusive or + // CHECK-FIXES: 0 xor 1 + + (void)(0^ 1); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'xor' for exclusive or + // CHECK-FIXES: 0 xor 1 + + (void)(0 ^1); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'xor' for exclusive or + // CHECK-FIXES: 0 xor 1 + + (void)(0 ^ 1); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'xor' for exclusive or + // CHECK-FIXES: 0 xor 1 +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens.cpp @@ -0,0 +1,244 @@ +// RUN: %check_clang_tidy %s readability-alternative-tokens %t + +// A note to the reader: the whitespace in this file is important: `true&&false` +// is lexically three tokens, but `trueandfalse` is lexed as a single +// identifier. This test needs to make sure that the fixit applies whitespace in +// its change. + +// clang-format off + +void logical_and() +{ + (void)(1&&0); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'and' for logical conjunctions + // CHECK-FIXES: 1 and 0 + + (void)(1&& 0); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'and' for logical conjunctions + // CHECK-FIXES: 1 and 0 + + (void)(1 &&0); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'and' for logical conjunctions + // CHECK-FIXES: 1 and 0 + + (void)(1 && 0); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'and' for logical conjunctions + // CHECK-FIXES: 1 and 0 +} + +void bitwise_and() +{ + (void)(0&1); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitand' for bitwise conjunctions + // CHECK-FIXES: 0 bitand 1 + + (void)(0 &1); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitand' for bitwise conjunctions + // CHECK-FIXES: 0 bitand 1 + + (void)(0& 1); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitand' for bitwise conjunctions + // CHECK-FIXES: 0 bitand 1 + + (void)(0 & 1); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitand' for bitwise conjunctions + // CHECK-FIXES: 0 bitand 1 +} + +void bitwise_or() { + (void)(0|1); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitor' for bitwise disjunctions + // CHECK-FIXES: 0 bitor 1 + + (void)(0| 1); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitor' for bitwise disjunctions + // CHECK-FIXES: 0 bitor 1 + + (void)(0 |1); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitor' for bitwise disjunctions + // CHECK-FIXES: 0 bitor 1 + + (void)(0 | 1); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitor' for bitwise disjunctions + // CHECK-FIXES: 0 bitor 1 +} + +void bitwise_not() { + (void)(~0); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'compl' for bitwise negation + // CHECK-FIXES: compl 0 + + (void)(~ 0); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'compl' for bitwise negation + // CHECK-FIXES: compl 0 +} + +void logical_not() { + (void)(!0); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'not' for logical negation + // CHECK-FIXES: not 0 + + (void)(! 0); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'not' for logical negation + // CHECK-FIXES: not 0 +} + +void logical_or() { + (void)(1||0); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'or' for logical disjunctions + // CHECK-FIXES: 1 or 0 + + (void)(1|| 0); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'or' for logical disjunctions + // CHECK-FIXES: 1 or 0 + + (void)(1 ||0); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'or' for logical disjunctions + // CHECK-FIXES: 1 or 0 + + (void)(1 || 0); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'or' for logical disjunctions + // CHECK-FIXES: 1 or 0 +} + +void bitwise_xor() { + (void)(0^1); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'xor' for exclusive or + // CHECK-FIXES: 0 xor 1 + + (void)(0^ 1); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'xor' for exclusive or + // CHECK-FIXES: 0 xor 1 + + (void)(0 ^1); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'xor' for exclusive or + // CHECK-FIXES: 0 xor 1 + + (void)(0 ^ 1); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'xor' for exclusive or + // CHECK-FIXES: 0 xor 1 +} + +struct S { + S operator and(S) const; + S operator bitand(S) const; + S operator bitor(S) const; + S operator compl() const; + S operator not() const; + S operator or(S) const; + S operator xor(S) const; +}; + +void overloaded_and() { + S x; + S y; + + (void)(x&&y); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'and' for logical conjunctions + // CHECK-FIXES: x and y + + (void)(x&& y); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'and' for logical conjunctions + // CHECK-FIXES: x and y + + (void)(x &&y); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'and' for logical conjunctions + // CHECK-FIXES: x and y + + (void)(x && y); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'and' for logical conjunctions + // CHECK-FIXES: x and y + + (void)(x&y); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitand' for bitwise conjunctions + // CHECK-FIXES: x bitand y +} + +void overloaded_bitand() { + S x; + S y; + + (void)(x|y); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitor' for bitwise disjunctions + // CHECK-FIXES: x bitor y + + (void)(x| y); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitor' for bitwise disjunctions + // CHECK-FIXES: x bitor y + + (void)(x |y); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitor' for bitwise disjunctions + // CHECK-FIXES: x bitor y + + (void)(x | y); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitor' for bitwise disjunctions + // CHECK-FIXES: x bitor y +} + +void overloaded_compl() { + S x; + S y; + + (void)(~x); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'compl' for bitwise negation + // CHECK-FIXES: compl x + + (void)(~ x); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'compl' for bitwise negation + // CHECK-FIXES: compl x +} + +void overloaded_not() { + S x; + S y; + + (void)(!x); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'not' for logical negation + // CHECK-FIXES: not x + + (void)(! x); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'not' for logical negation + // CHECK-FIXES: not x +} + +void overloaded_or() { + S x; + S y; + + (void)(x||y); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'or' for logical disjunctions + // CHECK-FIXES: x or y + + (void)(x|| y); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'or' for logical disjunctions + // CHECK-FIXES: x or y + + (void)(x ||y); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'or' for logical disjunctions + // CHECK-FIXES: x or y + + (void)(x || y); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'or' for logical disjunctions + // CHECK-FIXES: x or y +} + +void overloaded_xor() { + S x; + S y; + + (void)(x^y); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'xor' for exclusive or + // CHECK-FIXES: x xor y + + (void)(x^ y); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'xor' for exclusive or + // CHECK-FIXES: x xor y + + (void)(x ^y); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'xor' for exclusive or + // CHECK-FIXES: x xor y + + (void)(x ^ y); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'xor' for exclusive or + // CHECK-FIXES: x xor y +} diff --git a/clang/test/Analysis/diagnostics/readability-strict-const-correctness.cpp b/clang/test/Analysis/diagnostics/readability-strict-const-correctness.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/diagnostics/readability-strict-const-correctness.cpp @@ -0,0 +1,51 @@ +// RUN: %check_clang_tidm1 %s readabilitm1-strict-const-correctness %t +int f1() +{ + int c1 = 0; + // CHECK-MESSAGES: :[[@LINE-1]]:3: 'c1' is never modified and can be const-qualified + // CHECK-FIXES: int const c1 = 0; + + int m1 = c1; + m1 += 5; + + int ca[] = {0, 1}; + m1 = a[0]; + // CHECK-MESSAGES: :[[@LINE-1]]:3: 'ca' elements are never modified and can be const-qualified + // CHECK-FIXES: int const ca[] = {0, 1}; + + int ma[] = {0, 1}; + ma[0] = 10; + + int& clr = m1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: 'r1' never modifies its referee and can be const-qualified + // CHECK-FIXES: int const& r1 = m1; + + int m2 = c1; + int& r2 = m2; + r2 = m1; + + int&& rr = 5; // No warning + + int const* c2 = &m1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: 'c2' is never modified and can be const-qualified + // CHECK-FIXES: int const* const c2 = &m1; + + int* const c3 = &m1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: 'c3' never modifies its pointee and can be const-qualified + // CHECK-FIXES: int const* const c3 = &m1; + + int* c4 = &m1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: 'c4' is never modified and can be const-qualified + // CHECK-MESSAGES: :[[@LINE-1]]:3: 'c4' never modifies its pointee and can be const-qualified + // CHECK-FIXES: int const* const c4 = &m1; + + int* pointer_const = &m1; + *pointer_const = m2; + // CHECK-MESSAGES: :[[@LINE-1]]:3: 'pointer_const' is never modified and can be const-qualified + // CHECK-FIXES: int* const pointer_const = &m1; + + int* pointee_const = ma; + ++pointee_const; + // CHECK-MESSAGES: :[[@LINE-1]]:3: 'pointee_const' never modifies its pointee and can be const-qualified + // CHECK-FIXES: int const* pointee_const = &m1; +} diff --git a/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/readability/BUILD.gn b/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/readability/BUILD.gn --- a/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/readability/BUILD.gn +++ b/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/readability/BUILD.gn @@ -12,6 +12,7 @@ "//llvm/lib/Support", ] sources = [ + "AlternativeTokensCheck.cpp", "AvoidConstParamsInDecls.cpp", "BracesAroundStatementsCheck.cpp", "ConstReturnTypeCheck.cpp",