11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 22 AST_MATCHER(StringLiteral, lengthIsOne) {
return Node.getLength() == 1; }
24 ::internal::Matcher<Expr>
25 constructExprWithArg(llvm::StringRef ClassName,
26 const ::internal::Matcher<Expr> &Arg) {
27 auto ConstrExpr = cxxConstructExpr(hasType(recordDecl(hasName(ClassName))),
28 hasArgument(0, ignoringParenCasts(Arg)));
30 return anyOf(ConstrExpr, cxxBindTemporaryExpr(has(ConstrExpr)));
33 ::internal::Matcher<Expr>
34 copyConstructExprWithArg(llvm::StringRef ClassName,
35 const ::internal::Matcher<Expr> &Arg) {
36 return constructExprWithArg(ClassName, constructExprWithArg(ClassName, Arg));
39 llvm::Optional<std::string> makeCharacterLiteral(
const StringLiteral *Literal) {
42 llvm::raw_string_ostream Stream(Result);
43 Literal->outputString(Stream);
49 if (Result == R
"("'")") 50 return std::string(R
"('\'')"); 52 assert(Result.size() == 3 || (Result.size() == 4 && Result.substr(0, 2) == "\"\\"));
55 auto Pos = Result.find_first_of(
'"');
56 if (
Pos == Result.npos)
59 Pos = Result.find_last_of(
'"');
60 if (
Pos == Result.npos)
68 void FasterStrsplitDelimiterCheck::registerMatchers(MatchFinder *Finder) {
69 if (!getLangOpts().CPlusPlus)
73 const auto SingleChar =
74 expr(ignoringParenCasts(stringLiteral(lengthIsOne()).bind(
"Literal")));
79 copyConstructExprWithArg(
"::absl::string_view", SingleChar);
82 expr(copyConstructExprWithArg(
"::absl::ByAnyChar", StringViewArg))
87 Finder->addMatcher(callExpr(callee(functionDecl(hasName(
"::absl::StrSplit"))),
88 hasArgument(1, anyOf(ByAnyCharArg, SingleChar)),
89 unless(isInTemplateInstantiation()))
98 callee(functionDecl(hasName(
"::absl::MaxSplits"))),
99 hasArgument(0, anyOf(ByAnyCharArg, ignoringParenCasts(SingleChar))),
100 unless(isInTemplateInstantiation())),
104 void FasterStrsplitDelimiterCheck::check(
105 const MatchFinder::MatchResult &Result) {
106 const auto *Literal = Result.Nodes.getNodeAs<StringLiteral>(
"Literal");
108 if (Literal->getBeginLoc().isMacroID() || Literal->getEndLoc().isMacroID())
111 llvm::Optional<std::string> Replacement = makeCharacterLiteral(Literal);
114 SourceRange
Range = Literal->getSourceRange();
116 if (
const auto *ByAnyChar = Result.Nodes.getNodeAs<Expr>(
"ByAnyChar"))
117 Range = ByAnyChar->getSourceRange();
120 Literal->getBeginLoc(),
121 "%select{absl::StrSplit()|absl::MaxSplits()}0 called with a string " 123 "consisting of a single character; consider using the character overload")
124 << (Result.Nodes.getNodeAs<CallExpr>(
"StrSplit") ? 0 : 1)
125 << FixItHint::CreateReplacement(CharSourceRange::getTokenRange(Range),
AST_MATCHER(BinaryOperator, isAssignmentOperator)
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
CharSourceRange Range
SourceRange for the file name.