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 =
108 makeCharacterLiteral(Literal, *Result.Context);
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),