clang-tools 22.0.0git
SuspiciousStringviewDataUsageCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "../utils/Matchers.h"
12#include "clang/AST/ASTContext.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14
15using namespace clang::ast_matchers;
16
17namespace clang::tidy::bugprone {
18
20 StringRef Name, ClangTidyContext *Context)
21 : ClangTidyCheck(Name, Context),
22 StringViewTypes(utils::options::parseStringList(Options.get(
23 "StringViewTypes", "::std::basic_string_view;::llvm::StringRef"))),
24 AllowedCallees(
25 utils::options::parseStringList(Options.get("AllowedCallees", ""))) {}
26
29 Options.store(Opts, "StringViewTypes",
31 Options.store(Opts, "AllowedCallees",
33}
34
36 const LangOptions &LangOpts) const {
37 return LangOpts.CPlusPlus;
38}
39
40std::optional<TraversalKind>
44
46 auto AncestorCall = anyOf(
47 cxxConstructExpr(), callExpr(unless(cxxOperatorCallExpr())), lambdaExpr(),
48 initListExpr(
49 hasType(qualType(hasCanonicalType(hasDeclaration(recordDecl()))))));
50
51 auto DataMethod =
52 cxxMethodDecl(hasName("data"),
53 ofClass(matchers::matchesAnyListedName(StringViewTypes)));
54
55 auto SizeCall = cxxMemberCallExpr(
56 callee(cxxMethodDecl(hasAnyName("size", "length"))),
57 on(ignoringParenImpCasts(
58 matchers::isStatementIdenticalToBoundNode("self"))));
59
60 auto DescendantSizeCall = expr(hasDescendant(
61 expr(SizeCall, hasAncestor(expr(AncestorCall).bind("ancestor-size")),
62 hasAncestor(expr(equalsBoundNode("parent"),
63 equalsBoundNode("ancestor-size"))))));
64
65 Finder->addMatcher(
66 cxxMemberCallExpr(
67 on(ignoringParenImpCasts(expr().bind("self"))), callee(DataMethod),
68 expr().bind("data-call"),
69 hasParent(expr(anyOf(
70 invocation(
71 expr().bind("parent"), unless(cxxOperatorCallExpr()),
72 hasAnyArgument(
73 ignoringParenImpCasts(equalsBoundNode("data-call"))),
74 unless(hasAnyArgument(ignoringParenImpCasts(SizeCall))),
75 unless(hasAnyArgument(DescendantSizeCall)),
76 hasDeclaration(namedDecl(
77 unless(matchers::matchesAnyListedName(AllowedCallees))))),
78 initListExpr(expr().bind("parent"),
79 hasType(qualType(hasCanonicalType(hasDeclaration(
80 recordDecl(unless(matchers::matchesAnyListedName(
81 AllowedCallees))))))),
82 unless(DescendantSizeCall)))))),
83 this);
84}
85
87 const MatchFinder::MatchResult &Result) {
88 const auto *DataCallExpr =
89 Result.Nodes.getNodeAs<CXXMemberCallExpr>("data-call");
90 diag(DataCallExpr->getExprLoc(),
91 "result of a `data()` call may not be null terminated, provide size "
92 "information to the callee to prevent potential issues")
93 << DataCallExpr->getCallee()->getSourceRange();
94}
95
96} // namespace clang::tidy::bugprone
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
inline ::clang::ast_matchers::internal::Matcher< NamedDecl > matchesAnyListedName(llvm::ArrayRef< StringRef > NameList)
std::string serializeStringList(ArrayRef< StringRef > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
llvm::StringMap< ClangTidyValue > OptionMap