97 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "SuspiciousStringviewDataUsageCheck.h"10#include "../utils/Matchers.h"11#include "../utils/OptionsUtils.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 19SuspiciousStringviewDataUsageCheck::SuspiciousStringviewDataUsageCheck(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 27void SuspiciousStringviewDataUsageCheck::storeOptions(28 ClangTidyOptions::OptionMap &Opts) {29 Options.store(Opts, "StringViewTypes",30 utils::options::serializeStringList(StringViewTypes));31 Options.store(Opts, "AllowedCallees",32 utils::options::serializeStringList(AllowedCallees));33}34 35bool SuspiciousStringviewDataUsageCheck::isLanguageVersionSupported(36 const LangOptions &LangOpts) const {37 return LangOpts.CPlusPlus;38}39 40std::optional<TraversalKind>41SuspiciousStringviewDataUsageCheck::getCheckTraversalKind() const {42 return TK_AsIs;43}44 45void SuspiciousStringviewDataUsageCheck::registerMatchers(MatchFinder *Finder) {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 86void SuspiciousStringviewDataUsageCheck::check(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::bugprone97