12#include "clang/AST/ASTContext.h"
13#include "clang/AST/ASTDiagnostic.h"
14#include "clang/AST/Stmt.h"
15#include "clang/ASTMatchers/ASTMatchFinder.h"
16#include "clang/ASTMatchers/ASTMatchers.h"
17#include "clang/Basic/Diagnostic.h"
18#include "llvm/ADT/StringMap.h"
31 return hasCanonicalType(hasDeclaration(cxxRecordDecl(hasName(CharType))));
35 ASTContext &Context) {
37 findAll(returnStmt(hasReturnValue(ignoringParenImpCasts(
38 cxxTemporaryObjectExpr(argumentCountIs(0)).bind(
"temp_obj_expr"))))),
41 for (
const auto &Match : Matches)
42 if (
const auto *TempObjExpr =
43 Match.getNodeAs<CXXTemporaryObjectExpr>(
"temp_obj_expr");
44 TempObjExpr && TempObjExpr->getSourceRange().isValid())
45 Diag << FixItHint::CreateReplacement(TempObjExpr->getSourceRange(),
"{}");
51 IgnoredFunctions(
utils::options::parseStringList(
52 Options.get(
"IgnoredFunctions",
"toString$;ToString$;to_string$"))) {
53 parseReplacementStringViewClass(
54 Options.get(
"ReplacementStringViewClass",
""));
58 Options.store(Opts,
"IgnoredFunctions",
60 Options.store(Opts,
"ReplacementStringViewClass",
73 const auto IgnoredFunctionsMatcher =
75 const auto TernaryOperator = conditionalOperator(
76 hasTrueExpression(ignoringParenImpCasts(stringLiteral())),
77 hasFalseExpression(ignoringParenImpCasts(stringLiteral())));
78 const auto VirtualOrOperator =
79 cxxMethodDecl(anyOf(cxxConversionDecl(), isVirtual()));
83 unless(anyOf(VirtualOrOperator, IgnoredFunctionsMatcher,
84 ast_matchers::isExplicitTemplateSpecialization())),
85 returns(IsStdString), hasDescendant(returnStmt()),
86 unless(hasDescendant(returnStmt(hasReturnValue(unless(
87 anyOf(stringLiteral(), hasType(IsStdStringView), TernaryOperator,
88 cxxConstructExpr(anyOf(
89 allOf(hasType(IsStdString), argumentCountIs(0)),
90 allOf(isListInitialization(),
91 unless(cxxTemporaryObjectExpr()),
92 hasArgument(0, ignoringParenImpCasts(
93 stringLiteral()))))))))))))
99 const auto *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>(
"func");
101 bool ShouldAKA =
false;
102 const std::string DesugaredTypeStr =
103 clang::desugarForDiagnostic(
104 *Result.Context, QualType(MatchedDecl->getReturnType()), ShouldAKA)
106 const StringRef DestReturnTypeStr = toStringViewTypeStr(DesugaredTypeStr);
109 diag(MatchedDecl->getTypeSpecStartLoc(),
110 "consider using '%0' to avoid unnecessary copying and allocations")
111 << DestReturnTypeStr;
113 fixReturns(MatchedDecl, Diag, *Result.Context);
115 for (
const auto *
FuncDecl : MatchedDecl->redecls())
116 if (
const SourceRange ReturnTypeRange =
117 FuncDecl->getReturnTypeSourceRange();
118 ReturnTypeRange.isValid())
119 Diag << FixItHint::CreateReplacement(ReturnTypeRange, DestReturnTypeStr);
122StringRef UseStringViewCheck::toStringViewTypeStr(StringRef Type)
const {
123 if (Type.contains(
"wchar_t"))
124 return WStringViewClass;
125 if (Type.contains(
"char8_t"))
126 return U8StringViewClass;
127 if (Type.contains(
"char16_t"))
128 return U16StringViewClass;
129 if (Type.contains(
"char32_t"))
130 return U32StringViewClass;
131 return StringViewClass;
134void UseStringViewCheck::parseReplacementStringViewClass(StringRef Options) {
137 const llvm::StringMap<StringRef *> StringClassesMap{
144 const auto Split = Option.split(
'=');
145 if (
auto It = StringClassesMap.find(Split.first);
146 It != StringClassesMap.end())
147 *It->second = Split.second;
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
UseStringViewCheck(StringRef Name, ClangTidyContext *Context)
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
inline ::clang::ast_matchers::internal::Matcher< NamedDecl > matchesAnyListedRegexName(llvm::ArrayRef< StringRef > NameList)
static auto getStringTypeMatcher(StringRef CharType)
static constexpr StringRef WStringViewClassKey
static constexpr StringRef U32StringViewClassKey
static constexpr StringRef U8StringViewClassKey
static void fixReturns(const FunctionDecl *FuncDecl, DiagnosticBuilder &Diag, ASTContext &Context)
static constexpr StringRef StringViewClassKey
static constexpr StringRef U16StringViewClassKey
std::string serializeStringList(ArrayRef< StringRef > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
std::vector< StringRef > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
llvm::StringMap< ClangTidyValue > OptionMap
static constexpr const char FuncDecl[]