Index: clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tidy/misc/CMakeLists.txt +++ clang-tidy/misc/CMakeLists.txt @@ -16,6 +16,7 @@ MacroParenthesesCheck.cpp MacroRepeatedSideEffectsCheck.cpp MiscTidyModule.cpp + MiscStringCompareCheck.cpp MisplacedWideningCastCheck.cpp MoveConstantArgumentCheck.cpp MoveConstructorInitCheck.cpp Index: clang-tidy/misc/MiscStringCompareCheck.h =================================================================== --- clang-tidy/misc/MiscStringCompareCheck.h +++ clang-tidy/misc/MiscStringCompareCheck.h @@ -0,0 +1,36 @@ +//===--- MiscStringCompareCheck.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 MISC_STRING_COMPARE_CHECK_H +#define MISC_STRING_COMPARE_CHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace misc { + +/// This check flags all calls compare when used to check for string +/// equality or inequality. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc-string-compare-check.html +class MiscStringCompareCheck : public ClangTidyCheck { +public: + MiscStringCompareCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // MISC_STRING_COMPARE_CHECK_H Index: clang-tidy/misc/MiscStringCompareCheck.cpp =================================================================== --- clang-tidy/misc/MiscStringCompareCheck.cpp +++ clang-tidy/misc/MiscStringCompareCheck.cpp @@ -0,0 +1,68 @@ +//===--- MiscStringCompare.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 "MiscStringCompareCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +void MiscStringCompareCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus) + return; + const auto strCompare = cxxMemberCallExpr( + callee(cxxMethodDecl(hasName("compare"), + ofClass(classTemplateSpecializationDecl( + hasName("::std::basic_string"))))), + hasArgument(0, declRefExpr().bind("str2")), + callee(memberExpr().bind("mem"))); + + // First case: if(str.compare(str)) + Finder->addMatcher( + ifStmt(hasCondition(implicitCastExpr( + hasImplicitDestinationType(isInteger()), has(strCompare)))) + .bind("match"), + this); + + // Second case: if(!str.compare(str)) + Finder->addMatcher(ifStmt(hasCondition(unaryOperator( + hasOperatorName("!"), + hasUnaryOperand(implicitCastExpr( + hasImplicitDestinationType(isInteger()), + has(strCompare)))))) + .bind("match"), + this); + + // Third case: if(str.compare(str) == 0) + Finder->addMatcher(ifStmt(hasCondition(binaryOperator(hasOperatorName("=="), + hasLHS(strCompare)))) + .bind("match"), + this); + + // Fourth case: if(str.compare(str) != 0) + Finder->addMatcher(ifStmt(hasCondition(binaryOperator(hasOperatorName("!="), + hasLHS(strCompare)))) + .bind("match"), + this); +} + +void MiscStringCompareCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *Matched = Result.Nodes.getNodeAs("match")) + diag(Matched->getLocStart(), + "do not use compare to test equality of strings; " + "use the string equality operator instead"); +} + +} // namespace misc +} // namespace tidy +} // namespace clang Index: clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tidy/misc/MiscTidyModule.cpp +++ clang-tidy/misc/MiscTidyModule.cpp @@ -22,6 +22,7 @@ #include "InefficientAlgorithmCheck.h" #include "MacroParenthesesCheck.h" #include "MacroRepeatedSideEffectsCheck.h" +#include "MiscStringCompareCheck.h" #include "MisplacedConstCheck.h" #include "MisplacedWideningCastCheck.h" #include "MoveConstantArgumentCheck.h" @@ -105,6 +106,7 @@ CheckFactories.registerCheck( "misc-sizeof-expression"); CheckFactories.registerCheck("misc-static-assert"); + CheckFactories.registerCheck("misc-string-compare"); CheckFactories.registerCheck( "misc-string-constructor"); CheckFactories.registerCheck( Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -80,6 +80,7 @@ misc-sizeof-container misc-sizeof-expression misc-static-assert + misc-string-compare misc-string-constructor misc-string-integer-assignment misc-string-literal-with-embedded-nul Index: docs/clang-tidy/checks/misc-string-compare.rst =================================================================== --- docs/clang-tidy/checks/misc-string-compare.rst +++ docs/clang-tidy/checks/misc-string-compare.rst @@ -0,0 +1,31 @@ +.. title:: clang-tidy - misc-string-compare + +misc-string-compare +======================= + +Finds string comparisons using the compare method. + +A common mistake is to use the string's compare method instead of using the +equality or inequality operators. The compare method is intended for sorting +functions and thus returns -1, 0 or 1 depending on the lexicographical +relationship between the strings compared. If an equality or inequality check +can suffice, that is recommended. + +Examples: + +.. code-block:: c++ + + std::string str1{"a"}; + std::string str2{"b"}; + + if(str1.compare(str2)) {} // use str1 != str2 instead + + if(!str1.compare(str2)) {} // use str1 == str2 instead + + if(str1.compare(str2) == 0) {} // use str1 == str2 instead + + if(str1.compare(str2) != 0) {} // use str1 != str2 instead + +The above code examples shows the list of if-statements that this check will +give a warning for. All of them uses compare to check if equality or +inequality of two strings instead of using the correct operators.