diff options
| author | Alexander Kornienko <alexfh@google.com> | 2018-01-30 14:55:50 +0000 |
|---|---|---|
| committer | Alexander Kornienko <alexfh@google.com> | 2018-01-30 14:55:50 +0000 |
| commit | 5c9c0427bb5b733143861c817bebf0f170dbe3db (patch) | |
| tree | 525f45d14780062d4783e5db3ae419dc10fed960 /clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp | |
| parent | 4170f04576dabd55768a7eacd06e8eeb0282a7dd (diff) | |
| download | bcm5719-llvm-5c9c0427bb5b733143861c817bebf0f170dbe3db.tar.gz bcm5719-llvm-5c9c0427bb5b733143861c817bebf0f170dbe3db.zip | |
clang-tidy/rename_check.py misc-string-compare readability-string-compare
llvm-svn: 323766
Diffstat (limited to 'clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp')
| -rw-r--r-- | clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp new file mode 100644 index 00000000000..e75e80bb211 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -0,0 +1,82 @@ +//===--- 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 "StringCompareCheck.h" +#include "../utils/FixItHintUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Tooling/FixIt.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace readability { + +static const StringRef CompareMessage = "do not use 'compare' to test equality " + "of strings; use the string equality " + "operator instead"; + +void StringCompareCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus) + return; + + const auto StrCompare = cxxMemberCallExpr( + callee(cxxMethodDecl(hasName("compare"), + ofClass(classTemplateSpecializationDecl( + hasName("::std::basic_string"))))), + hasArgument(0, expr().bind("str2")), argumentCountIs(1), + callee(memberExpr().bind("str1"))); + + // First and second case: cast str.compare(str) to boolean. + Finder->addMatcher(implicitCastExpr(hasImplicitDestinationType(booleanType()), + has(StrCompare)) + .bind("match1"), + this); + + // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0. + Finder->addMatcher( + binaryOperator(anyOf(hasOperatorName("=="), hasOperatorName("!=")), + hasEitherOperand(StrCompare.bind("compare")), + hasEitherOperand(integerLiteral(equals(0)).bind("zero"))) + .bind("match2"), + this); +} + +void StringCompareCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *Matched = Result.Nodes.getNodeAs<Stmt>("match1")) { + diag(Matched->getLocStart(), CompareMessage); + return; + } + + if (const auto *Matched = Result.Nodes.getNodeAs<Stmt>("match2")) { + const ASTContext &Ctx = *Result.Context; + + if (const auto *Zero = Result.Nodes.getNodeAs<Stmt>("zero")) { + const auto *Str1 = Result.Nodes.getNodeAs<MemberExpr>("str1"); + const auto *Str2 = Result.Nodes.getNodeAs<Stmt>("str2"); + const auto *Compare = Result.Nodes.getNodeAs<Stmt>("compare"); + + auto Diag = diag(Matched->getLocStart(), CompareMessage); + + if (Str1->isArrow()) + Diag << FixItHint::CreateInsertion(Str1->getLocStart(), "*"); + + Diag << tooling::fixit::createReplacement(*Zero, *Str2, Ctx) + << tooling::fixit::createReplacement(*Compare, *Str1->getBase(), + Ctx); + } + } + + // FIXME: Add fixit to fix the code for case one and two (match1). +} + +} // namespace readability +} // namespace tidy +} // namespace clang |

