blob: ab2dff48a9fb7e0ecd9ad8341f2427b7b71ca887 [file] [log] [blame]
Samuel Benzaquen51e15232016-02-12 19:28:14 +00001//===--- FasterStringFindCheck.cpp - clang-tidy----------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "FasterStringFindCheck.h"
Etienne Bergeronde1ec032016-05-10 15:31:15 +000011#include "../utils/OptionsUtils.h"
Samuel Benzaquen51e15232016-02-12 19:28:14 +000012#include "clang/AST/ASTContext.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14#include "llvm/ADT/Optional.h"
15#include "llvm/Support/raw_ostream.h"
16
17using namespace clang::ast_matchers;
18
19namespace clang {
20namespace tidy {
21namespace performance {
22
23namespace {
24
Samuel Benzaquen51e15232016-02-12 19:28:14 +000025llvm::Optional<std::string> MakeCharacterLiteral(const StringLiteral *Literal) {
26 std::string Result;
27 {
28 llvm::raw_string_ostream OS(Result);
29 Literal->outputString(OS);
30 }
31 // Now replace the " with '.
32 auto pos = Result.find_first_of('"');
33 if (pos == Result.npos) return llvm::None;
34 Result[pos] = '\'';
35 pos = Result.find_last_of('"');
36 if (pos == Result.npos) return llvm::None;
37 Result[pos] = '\'';
38 return Result;
39}
40
Samuel Benzaquen51e15232016-02-12 19:28:14 +000041AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<Expr>,
42 hasSubstitutedType) {
43 return hasType(qualType(anyOf(substTemplateTypeParmType(),
44 hasDescendant(substTemplateTypeParmType()))));
45}
46
47} // namespace
48
49FasterStringFindCheck::FasterStringFindCheck(StringRef Name,
50 ClangTidyContext *Context)
51 : ClangTidyCheck(Name, Context),
Etienne Bergeronde1ec032016-05-10 15:31:15 +000052 StringLikeClasses(utils::options::parseStringList(
53 Options.get("StringLikeClasses", "std::basic_string"))) {
Samuel Benzaquen51e15232016-02-12 19:28:14 +000054}
55
56void FasterStringFindCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
57 Options.store(Opts, "StringLikeClasses",
Etienne Bergeronde1ec032016-05-10 15:31:15 +000058 utils::options::serializeStringList(StringLikeClasses));
Samuel Benzaquen51e15232016-02-12 19:28:14 +000059}
60
61void FasterStringFindCheck::registerMatchers(MatchFinder *Finder) {
62 if (!getLangOpts().CPlusPlus)
63 return;
64
65 const auto SingleChar =
Etienne Bergerone15ef2f2016-05-17 19:36:09 +000066 expr(ignoringParenCasts(stringLiteral(hasSize(1)).bind("literal")));
Samuel Benzaquen51e15232016-02-12 19:28:14 +000067
68 const auto StringFindFunctions =
69 anyOf(hasName("find"), hasName("rfind"), hasName("find_first_of"),
70 hasName("find_first_not_of"), hasName("find_last_of"),
71 hasName("find_last_not_of"));
72
73 llvm::Optional<ast_matchers::internal::Matcher<NamedDecl>> IsStringClass;
74
75 for (const auto &ClassName : StringLikeClasses) {
76 const auto HasName = hasName(ClassName);
77 IsStringClass = IsStringClass ? anyOf(*IsStringClass, HasName) : HasName;
78 }
79
80 if (IsStringClass) {
81 Finder->addMatcher(
82 cxxMemberCallExpr(
83 callee(functionDecl(StringFindFunctions).bind("func")),
84 anyOf(argumentCountIs(1), argumentCountIs(2)),
85 hasArgument(0, SingleChar),
86 on(expr(hasType(recordDecl(*IsStringClass)),
87 unless(hasSubstitutedType())))),
88 this);
89 }
90}
91
92void FasterStringFindCheck::check(const MatchFinder::MatchResult &Result) {
93 const auto *Literal = Result.Nodes.getNodeAs<StringLiteral>("literal");
94 const auto *FindFunc = Result.Nodes.getNodeAs<FunctionDecl>("func");
95
96 auto Replacement = MakeCharacterLiteral(Literal);
97 if (!Replacement)
98 return;
99
100 diag(Literal->getLocStart(), "%0 called with a string literal consisting of "
101 "a single character; consider using the more "
102 "effective overload accepting a character")
Benjamin Kramera62e2232016-04-07 14:55:25 +0000103 << FindFunc << FixItHint::CreateReplacement(
104 CharSourceRange::getTokenRange(Literal->getLocStart(),
105 Literal->getLocEnd()),
106 *Replacement);
Samuel Benzaquen51e15232016-02-12 19:28:14 +0000107}
108
109} // namespace performance
110} // namespace tidy
111} // namespace clang