27 assert(Literal->getLength() == 1 &&
28 "Only single character string should be matched");
29 assert(Literal->getCharByteWidth() == 1 &&
30 "StrSplit doesn't support wide char");
31 std::string Result = clang::tooling::fixit::getText(*Literal, Context).str();
32 bool IsRawStringLiteral = StringRef(Result).starts_with(R
"(R")");
35 if (IsRawStringLiteral) {
37 llvm::raw_string_ostream Stream(Result);
38 Literal->outputString(Stream);
43 if (Result == R
"("'")")
44 return std::string(R
"('\'')");
47 std::string::size_type Pos = Result.find_first_of(
'"');
48 if (Pos == std::string::npos)
51 Pos = Result.find_last_of(
'"');
52 if (Pos == std::string::npos)
60 const auto SingleChar =
61 expr(ignoringParenCasts(stringLiteral(lengthIsOne()).bind(
"Literal")));
65 auto StringViewArg = ignoringElidableConstructorCall(ignoringImpCasts(
66 cxxConstructExpr(hasType(recordDecl(hasName(
"::absl::string_view"))),
67 hasArgument(0, ignoringParenImpCasts(SingleChar)))));
72 expr(has(ignoringElidableConstructorCall(
73 ignoringParenCasts(cxxBindTemporaryExpr(has(cxxConstructExpr(
74 hasType(recordDecl(hasName(
"::absl::ByAnyChar"))),
75 hasArgument(0, StringViewArg))))))))
82 callExpr(callee(functionDecl(hasName(
"::absl::StrSplit"))),
83 hasArgument(1, anyOf(ByAnyCharArg, SingleChar)),
84 unless(isInTemplateInstantiation()))
93 callExpr(callee(functionDecl(hasName(
"::absl::MaxSplits"))),
94 hasArgument(0, anyOf(ByAnyCharArg,
95 ignoringParenCasts(SingleChar))),
96 unless(isInTemplateInstantiation()))),
101 const MatchFinder::MatchResult &Result) {
102 const auto *Literal = Result.Nodes.getNodeAs<StringLiteral>(
"Literal");
104 if (Literal->getBeginLoc().isMacroID() || Literal->getEndLoc().isMacroID())
107 std::optional<std::string> Replacement =
111 SourceRange Range = Literal->getSourceRange();
113 if (
const auto *ByAnyChar = Result.Nodes.getNodeAs<Expr>(
"ByAnyChar"))
114 Range = ByAnyChar->getSourceRange();
117 Literal->getBeginLoc(),
118 "%select{absl::StrSplit()|absl::MaxSplits()}0 called with a string "
120 "consisting of a single character; consider using the character overload")
121 << (Result.Nodes.getNodeAs<CallExpr>(
"StrSplit") ? 0 : 1)
122 << FixItHint::CreateReplacement(CharSourceRange::getTokenRange(Range),