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),
74 on(expr(hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(
75 recordDecl(hasAnyName(StringLikeClasses)))))),
76 unless(hasSubstitutedType())))),
81 const auto *Literal = Result.Nodes.getNodeAs<StringLiteral>(
"literal");
82 const auto *FindFunc = Result.Nodes.getNodeAs<FunctionDecl>(
"func");
84 auto Replacement = makeCharacterLiteral(Literal);
88 diag(Literal->getBeginLoc(),
"%0 called with a string literal consisting of "
89 "a single character; consider using the more "
90 "effective overload accepting a character")
92 << FixItHint::CreateReplacement(
93 CharSourceRange::getTokenRange(Literal->getBeginLoc(),
94 Literal->getEndLoc()),