10 #include "../utils/OptionsUtils.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "llvm/ADT/Optional.h"
14 #include "llvm/Support/raw_ostream.h"
20 namespace performance {
24 llvm::Optional<std::string> MakeCharacterLiteral(
const StringLiteral *Literal) {
27 llvm::raw_string_ostream
OS(Result);
28 Literal->outputString(
OS);
31 auto pos = Result.find_first_of(
'"');
32 if (pos == Result.npos)
35 pos = Result.find_last_of(
'"');
36 if (pos == Result.npos)
44 return hasType(qualType(anyOf(substTemplateTypeParmType(),
45 hasDescendant(substTemplateTypeParmType()))));
50 FasterStringFindCheck::FasterStringFindCheck(StringRef
Name,
54 Options.get(
"StringLikeClasses",
55 "::std::basic_string;::std::basic_string_view"))) {}
63 const auto SingleChar =
64 expr(ignoringParenCasts(stringLiteral(hasSize(1)).bind(
"literal")));
65 const auto StringFindFunctions =
66 hasAnyName(
"find",
"rfind",
"find_first_of",
"find_first_not_of",
67 "find_last_of",
"find_last_not_of");
71 callee(functionDecl(StringFindFunctions).bind(
"func")),
72 anyOf(argumentCountIs(1), argumentCountIs(2)),
73 hasArgument(0, SingleChar),
75 hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(
76 recordDecl(hasAnyName(SmallVector<StringRef, 4>(
77 StringLikeClasses.begin(), StringLikeClasses.end()))))))),
78 unless(hasSubstitutedType())))),
83 const auto *Literal = Result.Nodes.getNodeAs<StringLiteral>(
"literal");
84 const auto *FindFunc = Result.Nodes.getNodeAs<FunctionDecl>(
"func");
86 auto Replacement = MakeCharacterLiteral(Literal);
90 diag(Literal->getBeginLoc(),
"%0 called with a string literal consisting of "
91 "a single character; consider using the more "
92 "effective overload accepting a character")
94 << FixItHint::CreateReplacement(
95 CharSourceRange::getTokenRange(Literal->getBeginLoc(),
96 Literal->getEndLoc()),