29#include "llvm/ADT/APInt.h"
30#include "llvm/ADT/APSInt.h"
31#include "llvm/ADT/STLFunctionalExtras.h"
32#include "llvm/ADT/SmallVector.h"
33#include "llvm/ADT/StringRef.h"
49 std::string VisitBinaryOperator(
const BinaryOperator *BO) {
50 return "BinaryOperator(" + BO->
getOpcodeStr().str() +
")";
53 std::string VisitUnaryOperator(
const UnaryOperator *UO) {
57 std::string VisitImplicitCastExpr(
const ImplicitCastExpr *ICE) {
64static std::string getDREAncestorString(
const DeclRefExpr *DRE,
68 StmtDebugPrinter StmtPriner;
71 SS << StmtPriner.Visit(St);
75 if (StParents.
size() > 1)
76 return "unavailable due to multiple parents";
77 if (StParents.
empty())
96 virtual bool matches(
const DynTypedNode &DynNode, ASTContext &Ctx,
97 const UnsafeBufferUsageHandler &Handler) = 0;
98 virtual ~FastMatcher() =
default;
104 template <
typename T>
const T *getNodeAs(StringRef ID)
const {
105 auto It =
Nodes.find(ID);
106 if (It ==
Nodes.end()) {
109 return It->second.get<
T>();
112 void addNode(StringRef ID,
const DynTypedNode &Node) {
Nodes[
ID] = Node; }
115 llvm::StringMap<DynTypedNode>
Nodes;
119#define SIZED_CONTAINER_OR_VIEW_LIST \
120 "span", "array", "vector", "basic_string_view", "basic_string", \
131 bool FindAll,
bool IgnoreUnevaluatedContext,
133 : Matcher(&Matcher), FindAll(FindAll), Matches(
false),
134 IgnoreUnevaluatedContext(IgnoreUnevaluatedContext),
135 ActiveASTContext(&Context), Handler(&NewHandler) {
172 if (IgnoreUnevaluatedContext)
174 return DynamicRecursiveASTVisitor::TraverseGenericSelectionExpr(Node);
180 if (IgnoreUnevaluatedContext)
182 return DynamicRecursiveASTVisitor::TraverseUnaryExprOrTypeTraitExpr(Node);
186 bool TraverseQualifier)
override {
188 if (IgnoreUnevaluatedContext)
190 return DynamicRecursiveASTVisitor::TraverseTypeOfExprTypeLoc(
191 Node, TraverseQualifier);
195 bool TraverseQualifier)
override {
197 if (IgnoreUnevaluatedContext)
199 return DynamicRecursiveASTVisitor::TraverseDecltypeTypeLoc(
200 Node, TraverseQualifier);
205 if (IgnoreUnevaluatedContext)
207 return DynamicRecursiveASTVisitor::TraverseCXXNoexceptExpr(Node);
212 if (IgnoreUnevaluatedContext)
214 return DynamicRecursiveASTVisitor::TraverseCXXTypeidExpr(Node);
220 return DynamicRecursiveASTVisitor::TraverseCXXDefaultInitExpr(Node);
236 template <
typename T>
bool match(
const T &Node) {
246 FastMatcher *
const Matcher;
250 bool IgnoreUnevaluatedContext;
251 ASTContext *ActiveASTContext;
252 const UnsafeBufferUsageHandler *Handler;
267 FastMatcher &Matcher) {
275 FastMatcher &Matcher) {
303 const Stmt *S,
const llvm::function_ref<
void(
const Expr *)> OnResult) {
304 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(S);
305 CE && CE->getCastKind() == CastKind::CK_LValueToRValue)
306 OnResult(CE->getSubExpr());
307 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
315 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
324 if (
auto *CE = dyn_cast<CallExpr>(S)) {
325 if (
const auto *FnDecl = CE->getDirectCallee();
326 FnDecl && FnDecl->hasAttr<UnsafeBufferUsageAttr>())
335 if (
auto *CE = dyn_cast<CastExpr>(S)) {
336 if (CE->getCastKind() != CastKind::CK_PointerToIntegral &&
337 CE->getCastKind() != CastKind::CK_PointerToBoolean)
341 InnerMatcher(CE->getSubExpr());
345 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
359 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
365 InnerMatcher(BO->
getLHS());
366 InnerMatcher(BO->
getRHS());
384 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
389 if (
auto *CS = dyn_cast<CompoundStmt>(S)) {
390 for (
auto *Child : CS->body())
393 if (
auto *IfS = dyn_cast<IfStmt>(S)) {
395 InnerMatcher(IfS->getThen());
397 InnerMatcher(IfS->getElse());
448 case Stmt::DeclRefExprClass:
450 case Stmt::BinaryOperatorClass: {
453 BO2->getLHS(), BO2->getOpcode(),
479 dyn_cast<CXXMemberCallExpr>(Size->IgnoreParenImpCasts())) {
480 auto *DREOfPtr = dyn_cast<DeclRefExpr>(
481 MCEPtr->getImplicitObjectArgument()->IgnoreParenImpCasts());
482 auto *DREOfSize = dyn_cast<DeclRefExpr>(
483 MCESize->getImplicitObjectArgument()->IgnoreParenImpCasts());
485 if (!DREOfPtr || !DREOfSize)
489 if (DREOfPtr->getDecl() != DREOfSize->getDecl())
491 if (MCEPtr->getMethodDecl()->getName() !=
"data")
494 if (!MCEPtr->getRecordDecl()->isInStdNamespace())
497 auto *ObjII = MCEPtr->getRecordDecl()->getIdentifier();
504 if (!((AcceptSizeBytes &&
505 MCESize->getMethodDecl()->getName() ==
"size_bytes") ||
510 MCESize->getMethodDecl()->getName() ==
"size"))
520 if (Size->EvaluateAsInt(ER, Ctx)) {
526 return llvm::APSInt::compareValues(
527 SizeInt, llvm::APSInt(CAT->getSize(),
true)) == 0;
535 return UO && UO->
getOpcode() == UnaryOperator::Opcode::UO_AddrOf;
537 auto *FnDecl = CE->getDirectCallee();
539 return FnDecl && FnDecl->getNameAsString() ==
"addressof" &&
540 FnDecl->isInStdNamespace();
568 "expecting a two-parameter std::span constructor");
571 auto HaveEqualConstantValues = [&Ctx](
const Expr *E0,
const Expr *E1) {
573 if (
auto E1CV = E1->getIntegerConstantExpr(Ctx)) {
574 return llvm::APSInt::compareValues(*E0CV, *E1CV) == 0;
578 auto AreSameDRE = [](
const Expr *E0,
const Expr *E1) {
579 if (
auto *DRE0 = dyn_cast<DeclRefExpr>(E0))
580 if (
auto *DRE1 = dyn_cast<DeclRefExpr>(E1)) {
581 return DRE0->getDecl() == DRE1->getDecl();
587 if (Arg1CV && Arg1CV->isZero())
593 case Stmt::CXXNewExprClass:
596 return AreSameDRE((*Size)->IgnoreImplicit(), Arg1) ||
597 HaveEqualConstantValues(*Size, Arg1);
602 return Arg1CV && Arg1CV->isOne();
610 if (
auto CCast = dyn_cast<CStyleCastExpr>(Arg0)) {
611 if (!CCast->getType()->isPointerType())
619 if (
const auto *
Call = dyn_cast<CallExpr>(CCast->getSubExpr())) {
621 if (
auto *AllocAttr = FD->getAttr<AllocSizeAttr>()) {
622 const Expr *EleSizeExpr =
623 Call->getArg(AllocAttr->getElemSizeParam().getASTIndex());
625 ParamIdx NumElemIdx = AllocAttr->getNumElemsParam();
632 if (
auto BO = dyn_cast<BinaryOperator>(Arg1))
639 auto IsMethodCallToSizedObject = [](
const Stmt *Node, StringRef MethodName) {
640 if (
const auto *MC = dyn_cast<CXXMemberCallExpr>(Node)) {
641 const auto *MD = MC->getMethodDecl();
642 const auto *RD = MC->getRecordDecl();
645 if (
auto *II = RD->getDeclName().getAsIdentifierInfo();
646 II && RD->isInStdNamespace())
649 MD->getName() == MethodName;
654 if (IsMethodCallToSizedObject(Arg0,
"begin") &&
655 IsMethodCallToSizedObject(Arg1,
"end"))
659 ->getImplicitObjectArgument()
660 ->IgnoreParenImpCasts(),
662 ->getImplicitObjectArgument()
663 ->IgnoreParenImpCasts());
671 const bool IgnoreStaticSizedArrays) {
680 if (
const auto *CATy =
681 dyn_cast<ConstantArrayType>(Node.
getBase()
685 limit = CATy->getLimitedSize();
686 }
else if (
const auto *SLiteral = dyn_cast<clang::StringLiteral>(
688 limit = SLiteral->getLength() + 1;
693 if (IgnoreStaticSizedArrays) {
703 llvm::APSInt ArrIdx = EVResult.
Val.
getInt();
706 if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit)
708 }
else if (
const auto *BE = dyn_cast<BinaryOperator>(IndexExpr)) {
711 if (BE->getOpcode() != BO_And && BE->getOpcode() != BO_Rem)
714 const Expr *LHS = BE->getLHS();
715 const Expr *RHS = BE->getRHS();
717 if (BE->getOpcode() == BO_Rem) {
724 llvm::APSInt result = EVResult.
Val.
getInt();
725 if (result.isNonNegative() && result.getLimitedValue() <= limit)
736 llvm::APSInt result = EVResult.
Val.
getInt();
737 if (result.isNonNegative() && result.getLimitedValue() < limit)
751 if (
const auto *CE = dyn_cast<ConditionalOperator>(E)) {
753 const auto *
Cond = CE->getCond();
755 if (!
Cond->isValueDependent() &&
756 Cond->EvaluateAsBooleanCondition(CondEval, Ctx))
757 return CondEval ? CE->getLHS() : CE->getRHS();
767 if (
const auto *DefaultArgE = dyn_cast<CXXDefaultArgExpr>(Ptr))
775 if (
const auto *CondE = dyn_cast<ConditionalOperator>(Ptr)) {
784 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Ptr)) {
794 static const llvm::StringSet<> NullTermFunctions = {
"strerror"};
795 if (
auto *CE = dyn_cast<CallExpr>(Ptr)) {
812 if (
const auto *UO = dyn_cast<UnaryOperator>(Ptr)) {
813 if (UO->
getOpcode() != UnaryOperator::Opcode::UO_AddrOf)
819 if (
const auto *CE = dyn_cast<CallExpr>(Ptr)) {
824 return CE->getArg(0)->IgnoreParenImpCasts();
834 const auto *SizeOfExpr =
836 if (!SizeOfExpr || SizeOfExpr->getKind() != UETT_SizeOf)
838 if (SizeOfExpr->isArgumentType())
840 return SizeOfExpr->getArgumentExpr()->IgnoreParenImpCasts();
859 StringRef
matchName(StringRef FunName,
bool isBuiltin) {
861 if (isBuiltin && FunName.starts_with(
"__builtin_"))
865 FunName.drop_front(10 ));
867 if (FunName.starts_with(
"__asan_"))
875 if (Name.starts_with(
"__") && Name.ends_with(
"_chk"))
877 Name.drop_front(2).drop_back(4) );
882 if (Name.ends_with(
"_s"))
883 return Name.drop_back(2 );
900 const Expr *&UnsafeArg,
const unsigned FmtIdx,
901 std::optional<const unsigned> FmtArgIdx = std::nullopt,
902 bool isKprintf =
false) {
903 class StringFormatStringHandler
907 const Expr *&UnsafeArg;
923 unsigned PArgIdx = Precision.
getArgIndex() + FmtArgIdx;
925 if (PArgIdx < Call->getNumArgs()) {
926 const Expr *PArg =
Call->getArg(PArgIdx);
929 if (
auto *CE = dyn_cast<CastExpr>(PArg);
930 CE && CE->getType()->isSignedIntegerType())
931 PArg = CE->getSubExpr();
936 analyze_printf::OptionalAmount::HowSpecified::Constant) {
938 llvm::APSInt PArgVal = llvm::APSInt(
948 StringFormatStringHandler(
const CallExpr *
Call,
unsigned FmtArgIdx,
950 :
Call(
Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx),
951 UnsafeArgSet(
false) {}
954 const char *startSpecifier,
955 unsigned specifierLen,
963 if (ArgIdx >=
Call->getNumArgs())
967 const Expr *Arg =
Call->getArg(ArgIdx);
977 bool IsArgTypeValid =
980 ?
ArgType->getPointeeType()->isWideCharType()
981 :
ArgType->getPointeeType()->isCharType());
984 Precision && IsArgTypeValid)
988 UnsafeArg =
Call->getArg(ArgIdx);
993 bool isUnsafeArgSet() {
return UnsafeArgSet; }
996 const Expr *Fmt =
Call->getArg(FmtIdx);
997 unsigned FmtArgStartingIdx =
998 FmtArgIdx.has_value() ?
static_cast<unsigned>(*FmtArgIdx) : FmtIdx + 1;
1001 if (SL->getCharByteWidth() == 1) {
1002 StringRef FmtStr = SL->getString();
1003 StringFormatStringHandler Handler(
Call, FmtArgStartingIdx, UnsafeArg,
1007 Handler, FmtStr.begin(), FmtStr.end(), Ctx.
getLangOpts(),
1009 Handler.isUnsafeArgSet();
1012 if (
auto FmtStr = SL->tryEvaluateString(Ctx)) {
1013 StringFormatStringHandler Handler(
Call, FmtArgStartingIdx, UnsafeArg,
1016 Handler, FmtStr->data(), FmtStr->data() + FmtStr->size(),
1018 Handler.isUnsafeArgSet();
1024 return llvm::any_of(
1025 llvm::make_range(
Call->arg_begin() + FmtIdx,
Call->arg_end()),
1026 [&UnsafeArg, &Ctx](
const Expr *Arg) ->
bool {
1027 if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg, Ctx)) {
1045 static std::unique_ptr<std::set<StringRef>> PredefinedNames =
nullptr;
1046 if (!PredefinedNames)
1048 std::make_unique<std::set<StringRef>, std::set<StringRef>>({
1128 if (PredefinedNames->find(Name) != PredefinedNames->end())
1131 std::string NameWCS = Name.str();
1132 size_t WcsPos = NameWCS.find(
"wcs");
1134 while (WcsPos != std::string::npos) {
1135 NameWCS[WcsPos++] =
's';
1136 NameWCS[WcsPos++] =
't';
1137 NameWCS[WcsPos++] =
'r';
1138 WcsPos = NameWCS.find(
"wcs", WcsPos);
1140 if (PredefinedNames->find(NameWCS) != PredefinedNames->end())
1144 return Name.ends_with(
"scanf");
1152 assert(FD &&
"It should have been checked that FD is non-null.");
1160 if (Name !=
"memset")
1172 const auto *AddressOfVar = dyn_cast_if_present<DeclRefExpr>(
1177 const auto *SizeOfVar =
1182 return AddressOfVar->getDecl() != SizeOfVar->getDecl();
1197 if (!Name.ends_with(
"printf"))
1199 return Name.starts_with(
"v");
1213 if (!Name.ends_with(
"printf") ||
1215 Name.starts_with(
"v"))
1218 StringRef Prefix = Name.drop_back(6);
1220 if (Prefix.ends_with(
"w"))
1221 Prefix = Prefix.drop_back(1);
1222 return Prefix ==
"s";
1237 if (!Name.ends_with(
"printf") || Name.starts_with(
"v"))
1240 StringRef Prefix = Name.drop_back(6);
1242 if (Prefix.ends_with(
"w"))
1243 Prefix = Prefix.drop_back(1);
1245 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
1253 MatchResult &Result, llvm::StringRef Tag) {
1257 assert(FD &&
"It should have been checked that FD is non-null.");
1275 const Expr *UnsafeArg;
1286 bool isKprintf =
false;
1287 const Expr *UnsafeArg;
1290 isKprintf = II->getName() ==
"kprintf";
1292 std::nullopt, isKprintf)) {
1305 const Expr *UnsafeArg;
1316 for (
const auto *Arg : Node.
arguments())
1331 assert(FD &&
"It should have been checked that FD is non-null.");
1346 !Size->getType()->isUnsignedIntegerType())
1375#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1378 Gadget(Kind K) : K(K) {}
1380 Kind
getKind()
const {
return K; }
1383 StringRef getDebugName()
const {
1388#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1390 llvm_unreachable(
"Unhandled Gadget::Kind enum");
1394 virtual bool isWarningGadget()
const = 0;
1397 virtual SourceLocation getSourceLoc()
const = 0;
1402 virtual DeclUseList getClaimedVarUseSites()
const = 0;
1404 virtual ~Gadget() =
default;
1412class WarningGadget :
public Gadget {
1414 WarningGadget(Kind K) : Gadget(K) {}
1416 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1417 bool isWarningGadget() const final {
return true; }
1419 virtual void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1420 bool IsRelatedToDecl,
1421 ASTContext &Ctx)
const = 0;
1423 virtual SmallVector<const Expr *, 1> getUnsafePtrs()
const = 0;
1430class FixableGadget :
public Gadget {
1432 FixableGadget(Kind K) : Gadget(K) {}
1434 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1435 bool isWarningGadget() const final {
return false; }
1440 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1441 return std::nullopt;
1450 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1451 getStrategyImplications()
const {
1452 return std::nullopt;
1456static bool isSupportedVariable(
const DeclRefExpr &Node) {
1468 dyn_cast<ClassTemplateSpecializationDecl>(
RecordDecl);
1469 if (!class_template_specialization_decl)
1474 if (template_args.
size() == 0)
1485class UniquePtrArrayAccessGadget :
public WarningGadget {
1487 static constexpr const char *
const AccessorTag =
"unique_ptr_array_access";
1488 const CXXOperatorCallExpr *AccessorExpr;
1492 : WarningGadget(
Kind::UniquePtrArrayAccess),
1493 AccessorExpr(
Result.getNodeAs<CXXOperatorCallExpr>(AccessorTag)) {
1494 assert(AccessorExpr &&
1495 "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr");
1498 static bool classof(
const Gadget *G) {
1499 return G->getKind() == Kind::UniquePtrArrayAccess;
1502 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1505 const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(S);
1506 if (!OpCall || OpCall->
getOperator() != OO_Subscript)
1513 const CXXMethodDecl *
Method =
1518 if (
Method->getOverloadedOperator() != OO_Subscript)
1522 if (!isUniquePtrArray(RecordDecl))
1525 const Expr *IndexExpr = OpCall->
getArg(1);
1526 clang::Expr::EvalResult Eval;
1532 Result.addNode(AccessorTag, DynTypedNode::create(*OpCall));
1535 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1536 bool IsRelatedToDecl,
1537 ASTContext &Ctx)
const override {
1539 DynTypedNode::create(*AccessorExpr), IsRelatedToDecl, Ctx);
1542 SourceLocation getSourceLoc()
const override {
1544 return AccessorExpr->getOperatorLoc();
1545 return SourceLocation();
1548 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1549 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1552using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1553using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1557class IncrementGadget :
public WarningGadget {
1558 static constexpr const char *
const OpTag =
"op";
1559 const UnaryOperator *Op;
1563 : WarningGadget(
Kind::Increment),
1564 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1566 static bool classof(
const Gadget *G) {
1567 return G->getKind() == Kind::Increment;
1570 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1572 const auto *UO = dyn_cast<UnaryOperator>(S);
1577 Result.addNode(OpTag, DynTypedNode::create(*UO));
1581 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1582 bool IsRelatedToDecl,
1583 ASTContext &Ctx)
const override {
1586 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1588 DeclUseList getClaimedVarUseSites()
const override {
1589 SmallVector<const DeclRefExpr *, 2> Uses;
1590 if (
const auto *DRE =
1591 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1592 Uses.push_back(DRE);
1595 return std::move(Uses);
1598 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1599 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1605class DecrementGadget :
public WarningGadget {
1606 static constexpr const char *
const OpTag =
"op";
1607 const UnaryOperator *Op;
1611 : WarningGadget(
Kind::Decrement),
1612 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1614 static bool classof(
const Gadget *G) {
1615 return G->getKind() == Kind::Decrement;
1618 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1620 const auto *UO = dyn_cast<UnaryOperator>(S);
1625 Result.addNode(OpTag, DynTypedNode::create(*UO));
1629 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1630 bool IsRelatedToDecl,
1631 ASTContext &Ctx)
const override {
1634 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1636 DeclUseList getClaimedVarUseSites()
const override {
1637 if (
const auto *DRE =
1638 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1645 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1646 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1652class ArraySubscriptGadget :
public WarningGadget {
1653 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1654 const ArraySubscriptExpr *ASE;
1659 ASE(
Result.getNodeAs<ArraySubscriptExpr>(ArraySubscrTag)) {}
1661 static bool classof(
const Gadget *G) {
1662 return G->getKind() == Kind::ArraySubscript;
1665 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1666 const UnsafeBufferUsageHandler *Handler,
1668 const auto *ASE = dyn_cast<ArraySubscriptExpr>(S);
1671 const auto *
const Base = ASE->getBase()->IgnoreParenImpCasts();
1674 const auto *Idx = dyn_cast<IntegerLiteral>(ASE->getIdx());
1675 bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
1682 Result.addNode(ArraySubscrTag, DynTypedNode::create(*ASE));
1686 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1687 bool IsRelatedToDecl,
1688 ASTContext &Ctx)
const override {
1691 SourceLocation getSourceLoc()
const override {
return ASE->getBeginLoc(); }
1693 DeclUseList getClaimedVarUseSites()
const override {
1694 if (
const auto *DRE =
1695 dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
1702 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1703 return {ASE->getBase()->IgnoreParenImpCasts()};
1711class PointerArithmeticGadget :
public WarningGadget {
1712 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1713 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1714 const BinaryOperator *PA;
1719 : WarningGadget(
Kind::PointerArithmetic),
1720 PA(
Result.getNodeAs<BinaryOperator>(PointerArithmeticTag)),
1721 Ptr(
Result.getNodeAs<Expr>(PointerArithmeticPointerTag)) {}
1723 static bool classof(
const Gadget *G) {
1724 return G->getKind() == Kind::PointerArithmetic;
1727 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1729 const auto *BO = dyn_cast<BinaryOperator>(S);
1732 const auto *LHS = BO->
getLHS();
1733 const auto *RHS = BO->
getRHS();
1738 RHS->getType()->isEnumeralType())) {
1739 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*LHS));
1740 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1746 (LHS->getType()->isIntegerType() || LHS->getType()->isEnumeralType())) {
1747 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*RHS));
1748 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1754 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1755 bool IsRelatedToDecl,
1756 ASTContext &Ctx)
const override {
1759 SourceLocation getSourceLoc()
const override {
return PA->getBeginLoc(); }
1761 DeclUseList getClaimedVarUseSites()
const override {
1762 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts())) {
1769 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1770 return {Ptr->IgnoreParenImpCasts()};
1777class SpanTwoParamConstructorGadget :
public WarningGadget {
1778 static constexpr const char *
const SpanTwoParamConstructorTag =
1779 "spanTwoParamConstructor";
1780 const CXXConstructExpr *Ctor;
1784 : WarningGadget(
Kind::SpanTwoParamConstructor),
1785 Ctor(
Result.getNodeAs<CXXConstructExpr>(SpanTwoParamConstructorTag)) {}
1787 static bool classof(
const Gadget *G) {
1788 return G->getKind() == Kind::SpanTwoParamConstructor;
1792 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1795 const auto *CDecl = CE->getConstructor();
1796 const auto *CRecordDecl = CDecl->getParent();
1797 auto HasTwoParamSpanCtorDecl =
1798 CRecordDecl->isInStdNamespace() &&
1799 CDecl->getDeclName().getAsString() ==
"span" && CE->getNumArgs() == 2;
1802 Result.addNode(SpanTwoParamConstructorTag, DynTypedNode::create(*CE));
1806 static bool matches(
const Stmt *S, ASTContext &Ctx,
1807 const UnsafeBufferUsageHandler *Handler,
1814 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1815 bool IsRelatedToDecl,
1816 ASTContext &Ctx)
const override {
1819 SourceLocation getSourceLoc()
const override {
return Ctor->getBeginLoc(); }
1821 DeclUseList getClaimedVarUseSites()
const override {
1824 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->getArg(0))) {
1831 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1838class PointerInitGadget :
public FixableGadget {
1840 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1841 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1842 const VarDecl *PtrInitLHS;
1843 const DeclRefExpr *PtrInitRHS;
1847 : FixableGadget(
Kind::PointerInit),
1848 PtrInitLHS(
Result.getNodeAs<VarDecl>(PointerInitLHSTag)),
1849 PtrInitRHS(
Result.getNodeAs<DeclRefExpr>(PointerInitRHSTag)) {}
1851 static bool classof(
const Gadget *G) {
1852 return G->getKind() == Kind::PointerInit;
1855 static bool matches(
const Stmt *S,
1856 llvm::SmallVectorImpl<MatchResult> &Results) {
1857 const DeclStmt *DS = dyn_cast<DeclStmt>(S);
1866 const auto *DRE = dyn_cast<DeclRefExpr>(
Init->IgnoreImpCasts());
1867 if (!DRE || !
hasPointerType(*DRE) || !isSupportedVariable(*DRE)) {
1871 R.addNode(PointerInitLHSTag, DynTypedNode::create(*VD));
1872 R.addNode(PointerInitRHSTag, DynTypedNode::create(*DRE));
1873 Results.emplace_back(std::move(R));
1877 virtual std::optional<FixItList>
1878 getFixits(
const FixitStrategy &S)
const override;
1879 SourceLocation getSourceLoc()
const override {
1880 return PtrInitRHS->getBeginLoc();
1883 virtual DeclUseList getClaimedVarUseSites()
const override {
1884 return DeclUseList{PtrInitRHS};
1887 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1888 getStrategyImplications()
const override {
1889 return std::make_pair(PtrInitLHS,
cast<VarDecl>(PtrInitRHS->getDecl()));
1898class PtrToPtrAssignmentGadget :
public FixableGadget {
1900 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1901 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1902 const DeclRefExpr *PtrLHS;
1903 const DeclRefExpr *PtrRHS;
1907 : FixableGadget(
Kind::PtrToPtrAssignment),
1908 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1909 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1911 static bool classof(
const Gadget *G) {
1912 return G->getKind() == Kind::PtrToPtrAssignment;
1915 static bool matches(
const Stmt *S,
1916 llvm::SmallVectorImpl<MatchResult> &Results) {
1917 size_t SizeBefore = Results.size();
1919 const auto *BO = dyn_cast<BinaryOperator>(S);
1920 if (!BO || BO->
getOpcode() != BO_Assign)
1923 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1925 !isSupportedVariable(*RHSRef)) {
1928 const auto *LHS = BO->
getLHS();
1929 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1931 !isSupportedVariable(*LHSRef)) {
1935 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1936 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1937 Results.emplace_back(std::move(R));
1939 return SizeBefore != Results.size();
1942 virtual std::optional<FixItList>
1943 getFixits(
const FixitStrategy &S)
const override;
1944 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1946 virtual DeclUseList getClaimedVarUseSites()
const override {
1947 return DeclUseList{PtrLHS, PtrRHS};
1950 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1951 getStrategyImplications()
const override {
1962class CArrayToPtrAssignmentGadget :
public FixableGadget {
1964 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1965 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1966 const DeclRefExpr *PtrLHS;
1967 const DeclRefExpr *PtrRHS;
1971 : FixableGadget(
Kind::CArrayToPtrAssignment),
1972 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1973 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1975 static bool classof(
const Gadget *G) {
1976 return G->getKind() == Kind::CArrayToPtrAssignment;
1979 static bool matches(
const Stmt *S,
1980 llvm::SmallVectorImpl<MatchResult> &Results) {
1981 size_t SizeBefore = Results.size();
1983 const auto *BO = dyn_cast<BinaryOperator>(S);
1984 if (!BO || BO->
getOpcode() != BO_Assign)
1987 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1990 !isSupportedVariable(*RHSRef)) {
1993 const auto *LHS = BO->
getLHS();
1994 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1996 !isSupportedVariable(*LHSRef)) {
2000 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
2001 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
2002 Results.emplace_back(std::move(R));
2004 return SizeBefore != Results.size();
2007 virtual std::optional<FixItList>
2008 getFixits(
const FixitStrategy &S)
const override;
2009 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
2011 virtual DeclUseList getClaimedVarUseSites()
const override {
2012 return DeclUseList{PtrLHS, PtrRHS};
2015 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
2016 getStrategyImplications()
const override {
2023class UnsafeBufferUsageAttrGadget :
public WarningGadget {
2024 constexpr static const char *
const OpTag =
"attr_expr";
2029 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
2030 Op(
Result.getNodeAs<Expr>(OpTag)) {}
2032 static bool classof(
const Gadget *G) {
2033 return G->getKind() == Kind::UnsafeBufferUsageAttr;
2036 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2038 if (
auto *CE = dyn_cast<CallExpr>(S)) {
2039 if (CE->getDirectCallee() &&
2040 CE->getDirectCallee()->hasAttr<UnsafeBufferUsageAttr>()) {
2041 Result.addNode(OpTag, DynTypedNode::create(*CE));
2045 if (
auto *ME = dyn_cast<MemberExpr>(S)) {
2048 if (ME->getMemberDecl()->hasAttr<UnsafeBufferUsageAttr>()) {
2049 Result.addNode(OpTag, DynTypedNode::create(*ME));
2056 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2057 bool IsRelatedToDecl,
2058 ASTContext &Ctx)
const override {
2061 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2063 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2065 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2071class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
2072 constexpr static const char *
const OpTag =
"cxx_construct_expr";
2073 const CXXConstructExpr *Op;
2077 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
2078 Op(
Result.getNodeAs<CXXConstructExpr>(OpTag)) {}
2080 static bool classof(
const Gadget *G) {
2081 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
2085 const auto *CE = dyn_cast<CXXConstructExpr>(S);
2086 if (!CE || !CE->getConstructor()->hasAttr<UnsafeBufferUsageAttr>())
2090 if (SpanTwoParamConstructorGadget::matches(CE, Ctx, Tmp))
2092 Result.addNode(OpTag, DynTypedNode::create(*CE));
2096 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2097 bool IsRelatedToDecl,
2098 ASTContext &Ctx)
const override {
2101 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2103 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2105 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2112class DataInvocationGadget :
public WarningGadget {
2113 constexpr static const char *
const OpTag =
"data_invocation_expr";
2114 const ExplicitCastExpr *Op;
2118 : WarningGadget(
Kind::DataInvocation),
2119 Op(
Result.getNodeAs<ExplicitCastExpr>(OpTag)) {}
2121 static bool classof(
const Gadget *G) {
2122 return G->getKind() == Kind::DataInvocation;
2125 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2127 auto *CE = dyn_cast<ExplicitCastExpr>(S);
2130 for (
auto *Child : CE->children()) {
2131 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Child);
2132 MCE && isDataFunction(MCE)) {
2133 Result.addNode(OpTag, DynTypedNode::create(*CE));
2136 if (
auto *
Paren = dyn_cast<ParenExpr>(Child)) {
2137 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(
Paren->getSubExpr());
2138 MCE && isDataFunction(MCE)) {
2139 Result.addNode(OpTag, DynTypedNode::create(*CE));
2147 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2148 bool IsRelatedToDecl,
2149 ASTContext &Ctx)
const override {
2152 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2154 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2157 static bool isDataFunction(
const CXXMemberCallExpr *call) {
2164 if (method->getNameAsString() ==
"data" &&
2165 method->getParent()->isInStdNamespace() &&
2166 llvm::is_contained({SIZED_CONTAINER_OR_VIEW_LIST},
2167 method->getParent()->getName()))
2172 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2175class UnsafeLibcFunctionCallGadget :
public WarningGadget {
2176 const CallExpr *
const Call;
2177 const Expr *UnsafeArg =
nullptr;
2178 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
2180 constexpr static const char *
const UnsafeSprintfTag =
2181 "UnsafeLibcFunctionCall_sprintf";
2182 constexpr static const char *
const UnsafeSizedByTag =
2183 "UnsafeLibcFunctionCall_sized_by";
2184 constexpr static const char *
const UnsafeStringTag =
2185 "UnsafeLibcFunctionCall_string";
2186 constexpr static const char *
const UnsafeVaListTag =
2187 "UnsafeLibcFunctionCall_va_list";
2201 } WarnedFunKind = OTHERS;
2204 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2205 Call(
Result.getNodeAs<CallExpr>(Tag)) {
2206 if (
Result.getNodeAs<Decl>(UnsafeSprintfTag))
2207 WarnedFunKind = SPRINTF;
2208 else if (
auto *E =
Result.getNodeAs<Expr>(UnsafeStringTag)) {
2209 WarnedFunKind = STRING;
2211 }
else if (
Result.getNodeAs<CallExpr>(UnsafeSizedByTag)) {
2212 WarnedFunKind = SIZED_BY;
2213 UnsafeArg = Call->getArg(0);
2214 }
else if (
Result.getNodeAs<Decl>(UnsafeVaListTag))
2215 WarnedFunKind = VA_LIST;
2218 static bool matches(
const Stmt *S, ASTContext &Ctx,
2219 const UnsafeBufferUsageHandler *Handler,
2223 const auto *CE = dyn_cast<CallExpr>(S);
2226 const auto *FD = CE->getDirectCallee();
2230 const bool IsGlobalAndNotInAnyNamespace =
2231 FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
2235 if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
2242 const bool isSingleStringLiteralArg =
2243 CE->getNumArgs() == 1 &&
2245 if (!isSingleStringLiteralArg) {
2248 Result.addNode(Tag, DynTypedNode::create(*CE));
2252 Result.addNode(Tag, DynTypedNode::create(*CE));
2256 Result.addNode(Tag, DynTypedNode::create(*CE));
2257 Result.addNode(UnsafeVaListTag, DynTypedNode::create(*FD));
2261 Result.addNode(Tag, DynTypedNode::create(*CE));
2262 Result.addNode(UnsafeSprintfTag, DynTypedNode::create(*FD));
2268 Result.addNode(Tag, DynTypedNode::create(*CE));
2269 Result.addNode(UnsafeSizedByTag, DynTypedNode::create(*CE));
2274 Result.addNode(Tag, DynTypedNode::create(*CE));
2281 const Stmt *getBaseStmt()
const {
return Call; }
2283 SourceLocation getSourceLoc()
const override {
return Call->getBeginLoc(); }
2285 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2286 bool IsRelatedToDecl,
2287 ASTContext &Ctx)
const override {
2291 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2293 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2296class UnsafeFormatAttributedFunctionCallGadget :
public WarningGadget {
2297 const CallExpr *
const Call;
2298 const Expr *UnsafeArg =
nullptr;
2299 constexpr static const char *
const Tag =
"UnsafeFormatAttributedFunctionCall";
2300 constexpr static const char *
const UnsafeStringTag =
2301 "UnsafeFormatAttributedFunctionCall_string";
2305 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2306 Call(
Result.getNodeAs<CallExpr>(Tag)),
2307 UnsafeArg(
Result.getNodeAs<Expr>(UnsafeStringTag)) {}
2309 static bool matches(
const Stmt *S, ASTContext &Ctx,
2310 const UnsafeBufferUsageHandler *Handler,
2314 auto *CE = dyn_cast<CallExpr>(S);
2315 if (!CE || !CE->getDirectCallee())
2317 const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
2321 const FormatAttr *Attr =
nullptr;
2322 bool IsPrintf =
false;
2323 bool AnyAttr = llvm::any_of(
2324 FD->specific_attrs<FormatAttr>(),
2325 [&Attr, &IsPrintf](
const FormatAttr *FA) ->
bool {
2326 if (const auto *II = FA->getType()) {
2327 if (II->getName() ==
"printf" || II->getName() ==
"scanf") {
2329 IsPrintf = II->getName() ==
"printf";
2335 const Expr *UnsafeArg;
2341 unsigned FmtIdx = Attr->getFormatIdx() - 1;
2342 std::optional<unsigned> FmtArgIdx = Attr->getFirstArg() - 1;
2352 }
else if (CE->getStmtClass() != Stmt::CallExprClass &&
2355 if (*FmtArgIdx >= CE->getNumArgs())
2362 FmtArgIdx = std::nullopt;
2364 if (AnyAttr && !IsPrintf && FmtArgIdx) {
2366 Result.addNode(Tag, DynTypedNode::create(*CE));
2371 Ctx, CE, UnsafeArg, FmtIdx, FmtArgIdx)) {
2372 Result.addNode(Tag, DynTypedNode::create(*CE));
2373 Result.addNode(UnsafeStringTag, DynTypedNode::create(*UnsafeArg));
2379 const Stmt *getBaseStmt()
const {
return Call; }
2384 bool IsRelatedToDecl,
2389 UnsafeLibcFunctionCallGadget::UnsafeKind::STRING |
2390 UnsafeLibcFunctionCallGadget::UnsafeKind::FORMAT_ATTR,
2395 UnsafeLibcFunctionCallGadget::UnsafeKind::OTHERS |
2396 UnsafeLibcFunctionCallGadget::UnsafeKind::FORMAT_ATTR,
2400 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2408class ULCArraySubscriptGadget :
public FixableGadget {
2410 static constexpr const char *
const ULCArraySubscriptTag =
2411 "ArraySubscriptUnderULC";
2412 const ArraySubscriptExpr *Node;
2416 : FixableGadget(
Kind::ULCArraySubscript),
2417 Node(
Result.getNodeAs<ArraySubscriptExpr>(ULCArraySubscriptTag)) {
2418 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2421 static bool classof(
const Gadget *G) {
2422 return G->getKind() == Kind::ULCArraySubscript;
2425 static bool matches(
const Stmt *S,
2426 llvm::SmallVectorImpl<MatchResult> &Results) {
2427 size_t SizeBefore = Results.size();
2429 const auto *ASE = dyn_cast<ArraySubscriptExpr>(E);
2435 !isSupportedVariable(*DRE))
2438 R.addNode(ULCArraySubscriptTag, DynTypedNode::create(*ASE));
2439 Results.emplace_back(std::move(R));
2441 return SizeBefore != Results.size();
2444 virtual std::optional<FixItList>
2445 getFixits(
const FixitStrategy &S)
const override;
2446 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2448 virtual DeclUseList getClaimedVarUseSites()
const override {
2449 if (
const auto *DRE =
2450 dyn_cast<DeclRefExpr>(Node->getBase()->IgnoreImpCasts())) {
2460class UPCStandalonePointerGadget :
public FixableGadget {
2462 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
2463 const DeclRefExpr *Node;
2467 : FixableGadget(
Kind::UPCStandalonePointer),
2468 Node(
Result.getNodeAs<DeclRefExpr>(DeclRefExprTag)) {
2469 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2472 static bool classof(
const Gadget *G) {
2473 return G->getKind() == Kind::UPCStandalonePointer;
2476 static bool matches(
const Stmt *S,
2477 llvm::SmallVectorImpl<MatchResult> &Results) {
2478 size_t SizeBefore = Results.size();
2480 auto *E = dyn_cast<Expr>(S);
2485 !isSupportedVariable(*DRE))
2488 R.addNode(DeclRefExprTag, DynTypedNode::create(*DRE));
2489 Results.emplace_back(std::move(R));
2491 return SizeBefore != Results.size();
2494 virtual std::optional<FixItList>
2495 getFixits(
const FixitStrategy &S)
const override;
2496 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2498 virtual DeclUseList getClaimedVarUseSites()
const override {
return {Node}; }
2501class PointerDereferenceGadget :
public FixableGadget {
2502 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2503 static constexpr const char *
const OperatorTag =
"op";
2505 const DeclRefExpr *BaseDeclRefExpr =
nullptr;
2506 const UnaryOperator *Op =
nullptr;
2510 : FixableGadget(
Kind::PointerDereference),
2511 BaseDeclRefExpr(
Result.getNodeAs<DeclRefExpr>(BaseDeclRefExprTag)),
2512 Op(
Result.getNodeAs<UnaryOperator>(OperatorTag)) {}
2514 static bool classof(
const Gadget *G) {
2515 return G->getKind() == Kind::PointerDereference;
2518 static bool matches(
const Stmt *S,
2519 llvm::SmallVectorImpl<MatchResult> &Results) {
2520 size_t SizeBefore = Results.size();
2522 const auto *UO = dyn_cast<UnaryOperator>(S);
2525 const auto *CE = dyn_cast<Expr>(UO->
getSubExpr());
2528 CE = CE->IgnoreParenImpCasts();
2529 const auto *DRE = dyn_cast<DeclRefExpr>(CE);
2530 if (!DRE || !isSupportedVariable(*DRE))
2533 R.addNode(BaseDeclRefExprTag, DynTypedNode::create(*DRE));
2534 R.addNode(OperatorTag, DynTypedNode::create(*UO));
2535 Results.emplace_back(std::move(R));
2537 return SizeBefore != Results.size();
2540 DeclUseList getClaimedVarUseSites()
const override {
2541 return {BaseDeclRefExpr};
2544 virtual std::optional<FixItList>
2545 getFixits(
const FixitStrategy &S)
const override;
2546 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2552class UPCAddressofArraySubscriptGadget :
public FixableGadget {
2554 static constexpr const char *
const UPCAddressofArraySubscriptTag =
2555 "AddressofArraySubscriptUnderUPC";
2556 const UnaryOperator *Node;
2560 : FixableGadget(
Kind::ULCArraySubscript),
2561 Node(
Result.getNodeAs<UnaryOperator>(UPCAddressofArraySubscriptTag)) {
2562 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2565 static bool classof(
const Gadget *G) {
2566 return G->getKind() == Kind::UPCAddressofArraySubscript;
2569 static bool matches(
const Stmt *S,
2570 llvm::SmallVectorImpl<MatchResult> &Results) {
2571 size_t SizeBefore = Results.size();
2573 auto *E = dyn_cast<Expr>(S);
2577 if (!UO || UO->
getOpcode() != UO_AddrOf)
2579 const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->
getSubExpr());
2584 if (!DRE || !isSupportedVariable(*DRE))
2587 R.addNode(UPCAddressofArraySubscriptTag, DynTypedNode::create(*UO));
2588 Results.emplace_back(std::move(R));
2590 return SizeBefore != Results.size();
2593 virtual std::optional<FixItList>
2594 getFixits(
const FixitStrategy &)
const override;
2595 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2597 virtual DeclUseList getClaimedVarUseSites()
const override {
2610class DeclUseTracker {
2611 using UseSetTy = llvm::SmallPtrSet<const DeclRefExpr *, 16>;
2612 using DefMapTy = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
2615 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
2619 DeclUseTracker() =
default;
2620 DeclUseTracker(
const DeclUseTracker &) =
delete;
2621 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
2622 DeclUseTracker(DeclUseTracker &&) =
default;
2623 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
2626 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
2629 void claimUse(
const DeclRefExpr *DRE) {
2630 assert(Uses->count(DRE) &&
2631 "DRE not found or claimed by multiple matchers!");
2636 bool hasUnclaimedUses(
const VarDecl *VD)
const {
2638 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
2643 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
2645 for (
auto use : *Uses) {
2647 ReturnSet.insert(use);
2653 void discoverDecl(
const DeclStmt *DS) {
2654 for (
const Decl *D : DS->
decls()) {
2655 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
2666 const DeclStmt *lookupDecl(
const VarDecl *VD)
const {
2667 return Defs.lookup(VD);
2676 static constexpr const char *
const UPCPreIncrementTag =
2677 "PointerPreIncrementUnderUPC";
2682 : FixableGadget(Kind::UPCPreIncrement),
2684 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2688 return G->getKind() == Kind::UPCPreIncrement;
2697 size_t SizeBefore = Results.size();
2699 auto *E = dyn_cast<Expr>(S);
2703 if (!UO || UO->
getOpcode() != UO_PreInc)
2705 const auto *DRE = dyn_cast<DeclRefExpr>(UO->
getSubExpr());
2706 if (!DRE || !isSupportedVariable(*DRE))
2710 Results.emplace_back(std::move(R));
2712 return SizeBefore != Results.size();
2715 virtual std::optional<FixItList>
2720 return {dyn_cast<DeclRefExpr>(Node->getSubExpr())};
2728 static constexpr const char *
const UUCAddAssignTag =
2729 "PointerAddAssignUnderUUC";
2730 static constexpr const char *
const OffsetTag =
"Offset";
2733 const Expr *Offset =
nullptr;
2737 : FixableGadget(Kind::UUCAddAssign),
2740 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2744 return G->getKind() == Kind::UUCAddAssign;
2749 size_t SizeBefore = Results.size();
2751 const auto *E = dyn_cast<Expr>(S);
2755 if (!BO || BO->
getOpcode() != BO_AddAssign)
2757 const auto *DRE = dyn_cast<DeclRefExpr>(BO->
getLHS());
2763 Results.emplace_back(std::move(R));
2765 return SizeBefore != Results.size();
2768 virtual std::optional<FixItList>
2773 return {dyn_cast<DeclRefExpr>(Node->getLHS())};
2780 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2781 static constexpr const char *
const DerefOpTag =
"DerefOp";
2782 static constexpr const char *
const AddOpTag =
"AddOp";
2783 static constexpr const char *
const OffsetTag =
"Offset";
2792 : FixableGadget(Kind::DerefSimplePtrArithFixable),
2800 auto IsPtr = [](
const Expr *E, MatchResult &R) {
2804 if (!DRE || !isSupportedVariable(*DRE))
2809 const auto IsPlusOverPtrAndInteger = [&IsPtr](
const Expr *E,
2811 const auto *BO = dyn_cast<BinaryOperator>(E);
2815 const auto *LHS = BO->
getLHS();
2816 const auto *RHS = BO->
getRHS();
2829 size_t SizeBefore = Results.size();
2830 const auto InnerMatcher = [&IsPlusOverPtrAndInteger,
2831 &Results](
const Expr *E) {
2832 const auto *UO = dyn_cast<UnaryOperator>(E);
2838 if (IsPlusOverPtrAndInteger(Operand, R)) {
2840 Results.emplace_back(std::move(R));
2844 return SizeBefore != Results.size();
2847 virtual std::optional<FixItList>
2850 return DerefOp->getBeginLoc();
2854 return {BaseDeclRefExpr};
2862 : WarningGadgets(WarningGadgets) {}
2871#define WARNING_GADGET(name) \
2872 if (name##Gadget::matches(S, Ctx, Result) && \
2873 notInSafeBufferOptOut(*S, &Handler)) { \
2874 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2877#define WARNING_OPTIONAL_GADGET(name) \
2878 if (name##Gadget::matches(S, Ctx, &Handler, Result) && \
2879 notInSafeBufferOptOut(*S, &Handler)) { \
2880 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2883#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2888 WarningGadgetList &WarningGadgets;
2895 DeclUseTracker &Tracker)
2896 : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
2900 bool matchFound =
false;
2907#define FIXABLE_GADGET(name) \
2908 if (name##Gadget::matches(S, Results)) { \
2909 for (const auto &R : Results) { \
2910 FixableGadgets.push_back(std::make_unique<name##Gadget>(R)); \
2911 matchFound = true; \
2915#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2918 if (
auto *DRE = findDeclRefExpr(S); DRE) {
2919 Tracker.discoverUse(DRE);
2925 if (
auto *DS = findDeclStmt(S); DS) {
2926 Tracker.discoverDecl(DS);
2934 const auto *DRE = dyn_cast<DeclRefExpr>(S);
2942 const DeclStmt *findDeclStmt(
const Stmt *S) {
2943 const auto *DS = dyn_cast<DeclStmt>(S);
2948 FixableGadgetList &FixableGadgets;
2949 DeclUseTracker &Tracker;
2955 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2956 WarningGadgetList &WarningGadgets,
2957 DeclUseTracker &Tracker) {
2960 if (EmitSuggestions) {
2969 return N1->getBeginLoc().getRawEncoding() <
2970 N2->getBeginLoc().getRawEncoding();
2980 const Expr *UnsafeArg =
nullptr)
override {}
2988 bool IsRelatedToDecl,
3009 FixableGadgetList FixableGadgets;
3010 WarningGadgetList WarningGadgets;
3011 DeclUseTracker Tracker;
3012 MockReporter IgnoreHandler;
3015 FixableGadgets, WarningGadgets, Tracker);
3017 std::set<const Expr *>
Result;
3018 for (
auto &G : WarningGadgets) {
3019 for (
const Expr *E : G->getUnsafePtrs()) {
3028 std::map<const VarDecl *, std::set<const WarningGadget *>,
3042 for (
auto &G : AllUnsafeOperations) {
3043 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
3045 bool AssociatedWithVarDecl =
false;
3046 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
3047 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3048 result.
byVar[VD].insert(G.get());
3049 AssociatedWithVarDecl =
true;
3053 if (!AssociatedWithVarDecl) {
3054 result.
noVar.push_back(G.get());
3062 std::map<const VarDecl *, std::set<const FixableGadget *>,
3072 for (
auto &F : AllFixableOperations) {
3073 DeclUseList DREs = F->getClaimedVarUseSites();
3076 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3077 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
3081 return FixablesForUnsafeVars;
3088 std::vector<const FixItHint *>
All;
3092 std::sort(
All.begin(),
All.end(),
3094 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
3095 H2->RemoveRange.getBegin());
3103 Hint->RemoveRange.getBegin())) {
3115std::optional<FixItList>
3116PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
3119 switch (S.
lookup(LeftVD)) {
3123 return std::nullopt;
3125 return std::nullopt;
3128 return std::nullopt;
3130 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3132 return std::nullopt;
3136static inline std::optional<FixItList>
createDataFixit(
const ASTContext &Ctx,
3137 const DeclRefExpr *DRE);
3139std::optional<FixItList>
3140CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
3159 if (S.
lookup(LeftVD) == FixitStrategy::Kind::Span) {
3160 if (S.
lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
3163 }
else if (S.
lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
3164 if (S.
lookup(RightVD) == FixitStrategy::Kind::Array) {
3168 return std::nullopt;
3171std::optional<FixItList>
3172PointerInitGadget::getFixits(
const FixitStrategy &S)
const {
3173 const auto *LeftVD = PtrInitLHS;
3175 switch (S.
lookup(LeftVD)) {
3176 case FixitStrategy::Kind::Span:
3177 if (S.
lookup(RightVD) == FixitStrategy::Kind::Span)
3179 return std::nullopt;
3180 case FixitStrategy::Kind::Wontfix:
3181 return std::nullopt;
3182 case FixitStrategy::Kind::Iterator:
3183 case FixitStrategy::Kind::Array:
3184 return std::nullopt;
3185 case FixitStrategy::Kind::Vector:
3186 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3188 return std::nullopt;
3194 if (ConstVal->isNegative())
3201std::optional<FixItList>
3202ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
3203 if (
const auto *DRE =
3205 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3207 case FixitStrategy::Kind::Span: {
3211 const ASTContext &Ctx =
3214 return std::nullopt;
3218 case FixitStrategy::Kind::Array:
3220 case FixitStrategy::Kind::Wontfix:
3221 case FixitStrategy::Kind::Iterator:
3222 case FixitStrategy::Kind::Vector:
3223 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3226 return std::nullopt;
3229static std::optional<FixItList>
3232std::optional<FixItList>
3233UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
3234 auto DREs = getClaimedVarUseSites();
3238 case FixitStrategy::Kind::Span:
3240 case FixitStrategy::Kind::Wontfix:
3241 case FixitStrategy::Kind::Iterator:
3242 case FixitStrategy::Kind::Array:
3243 return std::nullopt;
3244 case FixitStrategy::Kind::Vector:
3245 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3247 return std::nullopt;
3252 static const char *
const EOL =
"\n";
3259 std::string
s = std::string(
"<# ");
3260 s += HintTextToUser;
3266template <
typename NodeTy>
3267static std::optional<SourceLocation>
3270 if (
unsigned TkLen =
3277 return std::nullopt;
3290 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
3291 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
3292 VD->getBeginLoc())) &&
3293 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
3294 At->getRange().getBegin()));
3298 AttrRangeOverlapping;
3340 std::optional<Qualifiers> Quals = std::nullopt) {
3341 const char *
const SpanOpen =
"std::span<";
3344 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
3345 return SpanOpen + EltTyText.str() +
'>';
3348std::optional<FixItList>
3350 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->getDecl());
3355 if (
auto ConstVal = Offset->getIntegerConstantExpr(Ctx))
3356 if (ConstVal->isNegative())
3357 return std::nullopt;
3378 const Expr *LHS = AddOp->getLHS(), *RHS = AddOp->getRHS();
3385 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
3387 return std::nullopt;
3392 std::optional<SourceLocation> AddOpLocation =
3394 std::optional<SourceLocation> DerefOpLocation =
3397 if (!AddOpLocation || !DerefOpLocation)
3398 return std::nullopt;
3408 return std::nullopt;
3411std::optional<FixItList>
3412PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
3423 if (
auto LocPastOperand =
3430 case FixitStrategy::Kind::Iterator:
3431 case FixitStrategy::Kind::Array:
3432 return std::nullopt;
3433 case FixitStrategy::Kind::Vector:
3434 llvm_unreachable(
"FixitStrategy not implemented yet!");
3435 case FixitStrategy::Kind::Wontfix:
3436 llvm_unreachable(
"Invalid strategy!");
3439 return std::nullopt;
3446 std::optional<SourceLocation> EndOfOperand =
3452 return std::nullopt;
3457std::optional<FixItList>
3458UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
3461 case FixitStrategy::Kind::Array:
3462 case FixitStrategy::Kind::Span: {
3467 case FixitStrategy::Kind::Wontfix:
3468 case FixitStrategy::Kind::Iterator:
3469 return std::nullopt;
3470 case FixitStrategy::Kind::Vector:
3471 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3474 return std::nullopt;
3479static std::optional<FixItList>
3486 const Expr *Idx = ArraySub->getIdx();
3489 std::stringstream SS;
3490 bool IdxIsLitZero =
false;
3493 if ((*ICE).isZero())
3494 IdxIsLitZero =
true;
3495 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
3497 return std::nullopt;
3501 SS << (*DreString).str() <<
".data()";
3503 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
3505 return std::nullopt;
3507 SS <<
"&" << (*DreString).str() <<
".data()"
3508 <<
"[" << (*IndexString).str() <<
"]";
3514std::optional<FixItList>
3518 if (DREs.size() != 1)
3519 return std::nullopt;
3521 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3525 const Stmt *AddAssignNode = Node;
3526 StringRef varName = VD->
getName();
3530 return std::nullopt;
3534 (Offset->IgnoreParens()->getBeginLoc() == Offset->getBeginLoc());
3535 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
3539 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
3541 if (!AddAssignLocation)
3542 return std::nullopt;
3549 Offset->getEndLoc().getLocWithOffset(1),
")"));
3553 return std::nullopt;
3556std::optional<FixItList>
3560 if (DREs.size() != 1)
3561 return std::nullopt;
3563 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3566 std::stringstream SS;
3567 StringRef varName = VD->
getName();
3571 SS <<
"(" << varName.data() <<
" = " << varName.data()
3572 <<
".subspan(1)).data()";
3573 std::optional<SourceLocation> PreIncLocation =
3575 if (!PreIncLocation)
3576 return std::nullopt;
3579 SourceRange(Node->getBeginLoc(), *PreIncLocation), SS.str()));
3583 return std::nullopt;
3601static std::optional<FixItList>
3603 const StringRef UserFillPlaceHolder) {
3611 if (
Init->isNullPointerConstant(
3616 NPC_ValueDependentIsNotNull)) {
3617 std::optional<SourceLocation> InitLocation =
3620 return std::nullopt;
3628 std::string ExtentText = UserFillPlaceHolder.data();
3629 StringRef One =
"1";
3634 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
3639 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
3640 if (!Ext->HasSideEffects(Ctx)) {
3641 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
3643 return std::nullopt;
3644 ExtentText = *ExtentString;
3646 }
else if (!CxxNew->isArray())
3658 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
3659 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
3660 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
3667 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
3670 return std::nullopt;
3672 StrBuffer.append(
", ");
3673 StrBuffer.append(ExtentText);
3674 StrBuffer.append(
"}");
3680#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
3681 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
3682 "failed to produce fixit for declaration '" + \
3683 (D)->getNameAsString() + "'" + (Msg))
3685#define DEBUG_NOTE_DECL_FAIL(D, Msg)
3691static std::optional<std::string>
3695 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3700 return std::nullopt;
3702 std::string SpanTyText =
"std::span<";
3704 SpanTyText.append(*PteTyText);
3706 if (PteTyQualifiers) {
3707 SpanTyText.append(
" ");
3708 SpanTyText.append(PteTyQualifiers->getAsString());
3710 SpanTyText.append(
">");
3729 const StringRef UserFillPlaceHolder,
3743 std::stringstream SS;
3748 std::optional<FixItList> InitFixIts =
3752 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
3753 std::make_move_iterator(InitFixIts->end()));
3760 if (!EndLocForReplacement.
isValid()) {
3810static std::optional<FixItList>
3816 return std::nullopt;
3821 std::vector<std::string> NewTysTexts(NumParms);
3822 std::vector<bool> ParmsMask(NumParms,
false);
3823 bool AtLeastOneParmToFix =
false;
3825 for (
unsigned i = 0; i < NumParms; i++) {
3832 return std::nullopt;
3834 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3835 std::optional<std::string> PteTyText =
3840 return std::nullopt;
3844 ParmsMask[i] =
true;
3845 AtLeastOneParmToFix =
true;
3847 if (!AtLeastOneParmToFix)
3854 const auto NewOverloadSignatureCreator =
3855 [&
SM, &LangOpts, &NewTysTexts,
3856 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3857 std::stringstream SS;
3865 SS << Prefix->str();
3867 return std::nullopt;
3871 for (
unsigned i = 0; i < NumParms; i++) {
3879 SS << NewTysTexts[i];
3882 SS <<
' ' << II->getName().str();
3883 }
else if (
auto ParmTypeText =
3887 SS << ParmTypeText->str();
3889 return std::nullopt;
3890 if (i != NumParms - 1)
3899 const auto OldOverloadDefCreator =
3900 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3901 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3902 std::stringstream SS;
3910 << FDPrefix->str() <<
"{";
3912 return std::nullopt;
3915 SS <<
"return " << FunQualName->str() <<
"(";
3917 return std::nullopt;
3921 for (
unsigned i = 0; i < NumParms; i++) {
3930 return std::nullopt;
3937 if (i != NumParms - 1)
3948 std::optional<SourceLocation> Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3952 if (FReDecl->isThisDeclarationADefinition()) {
3953 assert(FReDecl == FD &&
"inconsistent function definition");
3956 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3962 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3965 FReDecl->getBeginLoc(),
" ")));
3968 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3990 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
4006 std::stringstream SS;
4009 if (PteTyQualifiers)
4018 SS <<
' ' << PVDNameText->str();
4024 const DeclUseTracker &Tracker,
4027 const DeclStmt *DS = Tracker.lookupDecl(VD);
4030 " : variables declared this way not implemented yet");
4054 const QualType &ArrayEltT = CAT->getElementType();
4055 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
4064 auto MaybeElemTypeTxt =
4067 if (!MaybeElemTypeTxt)
4069 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
4074 while (NextTok && !NextTok->is(tok::l_square) &&
4087 if (!MaybeArraySizeTxt)
4089 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
4090 if (ArraySizeTxt.empty()) {
4101 std::optional<StringRef> IdentText =
4110 llvm::raw_svector_ostream OS(Replacement);
4111 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
4112 << IdentText->str();
4122 const DeclUseTracker &Tracker,
4125 const DeclStmt *DS = Tracker.lookupDecl(VD);
4126 assert(DS &&
"Fixing non-local variables not implemented yet!");
4145 const DeclUseTracker &Tracker,
ASTContext &Ctx,
4147 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
4148 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
4149 if (!FD || FD != D) {
4160 if (FD->isMain() || FD->isConstexpr() ||
4167 FD->isOverloadedOperator()) {
4176 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
4194 llvm_unreachable(
"FixitStrategy not implemented yet!");
4196 llvm_unreachable(
"Invalid strategy!");
4198 llvm_unreachable(
"Unknown strategy!");
4206 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
4208 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
4225 std::map<const VarDecl *, FixItList> &FixItsForVariable,
4230 for (
const auto &[VD, Ignore] : FixItsForVariable) {
4232 if (llvm::any_of(Grp,
4233 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
4234 return !FixItsForVariable.count(GrpMember);
4239 ToErase.push_back(
Member);
4242 for (
auto *VarToErase : ToErase)
4243 FixItsForVariable.erase(VarToErase);
4254 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
4258 FixItList FixItsSharedByParms{};
4260 std::optional<FixItList> OverloadFixes =
4263 if (OverloadFixes) {
4264 FixItsSharedByParms.append(*OverloadFixes);
4270 FixItsForVariable.erase(
Member);
4272 return FixItsSharedByParms;
4276static std::map<const VarDecl *, FixItList>
4285 std::map<const VarDecl *, FixItList> FixItsForVariable;
4290 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
4291 FixItsForVariable[VD] =
4295 if (FixItsForVariable[VD].empty()) {
4296 FixItsForVariable.erase(VD);
4299 for (
const auto &F : Fixables) {
4300 std::optional<FixItList> Fixits = F->getFixits(S);
4303 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
4304 Fixits->begin(), Fixits->end());
4309 VD, F->getSourceLoc(),
4310 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
4313 FixItsForVariable.erase(VD);
4332 FixItList FixItsSharedByParms{};
4334 if (
auto *FD = dyn_cast<FunctionDecl>(D))
4336 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
4340 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
4343 for (
auto &[Var, Ignore] : FixItsForVariable) {
4344 bool AnyParm =
false;
4345 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
4347 for (
const VarDecl *GrpMate : VarGroupForVD) {
4350 if (FixItsForVariable.count(GrpMate))
4351 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
4355 assert(!FixItsSharedByParms.empty() &&
4356 "Should not try to fix a parameter that does not belong to a "
4358 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
4365 for (
auto Iter = FinalFixItsForVariable.begin();
4366 Iter != FinalFixItsForVariable.end();)
4369 Iter = FinalFixItsForVariable.erase(Iter);
4372 return FinalFixItsForVariable;
4375template <
typename VarDeclIterTy>
4379 for (
const VarDecl *VD : UnsafeVars) {
4390 const std::vector<VarGrpTy> &Groups;
4391 const std::map<const VarDecl *, unsigned> &VarGrpMap;
4392 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
4396 const std::vector<VarGrpTy> &Groups,
4397 const std::map<const VarDecl *, unsigned> &VarGrpMap,
4398 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
4399 : Groups(Groups), VarGrpMap(VarGrpMap),
4400 GrpsUnionForParms(GrpsUnionForParms) {}
4403 if (GrpsUnionForParms.contains(Var)) {
4406 return GrpsUnionForParms.getArrayRef();
4411 auto It = VarGrpMap.find(Var);
4413 if (It == VarGrpMap.end())
4415 return Groups[It->second];
4419 return GrpsUnionForParms.getArrayRef();
4424 WarningGadgetList WarningGadgets,
4425 DeclUseTracker Tracker,
4427 bool EmitSuggestions) {
4428 if (!EmitSuggestions) {
4432 for (
const auto &G : WarningGadgets) {
4433 G->handleUnsafeOperation(Handler,
false,
4439 assert(FixableGadgets.empty() &&
4440 "Fixable gadgets found but suggestions not requested!");
4446 if (!WarningGadgets.empty()) {
4450 for (
const auto &G : FixableGadgets) {
4451 for (
const auto *DRE : G->getClaimedVarUseSites()) {
4452 Tracker.claimUse(DRE);
4468 if (WarningGadgets.empty())
4476 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
4479 for (
auto it = FixablesForAllVars.
byVar.cbegin();
4480 it != FixablesForAllVars.
byVar.cend();) {
4485 (
"failed to produce fixit for '" +
4486 it->first->getNameAsString() +
4487 "' : neither local nor a parameter"));
4489 it = FixablesForAllVars.
byVar.erase(it);
4490 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
4493 (
"failed to produce fixit for '" +
4494 it->first->getNameAsString() +
4495 "' : has a reference type"));
4497 it = FixablesForAllVars.
byVar.erase(it);
4498 }
else if (Tracker.hasUnclaimedUses(it->first)) {
4499 it = FixablesForAllVars.
byVar.erase(it);
4500 }
else if (it->first->isInitCapture()) {
4503 (
"failed to produce fixit for '" +
4504 it->first->getNameAsString() +
4505 "' : init capture"));
4507 it = FixablesForAllVars.
byVar.erase(it);
4514 for (
const auto &it : UnsafeOps.
byVar) {
4515 const VarDecl *
const UnsafeVD = it.first;
4516 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
4517 if (UnclaimedDREs.empty())
4521 std::string UnclaimedUseTrace =
4526 (
"failed to produce fixit for '" + UnfixedVDName +
4527 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
4528 UnclaimedUseTrace));
4535 llvm::DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
4536 DepMapTy DependenciesMap{};
4537 DepMapTy PtrAssignmentGraph{};
4539 for (
const auto &it : FixablesForAllVars.
byVar) {
4540 for (
const FixableGadget *fixable : it.second) {
4541 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
4542 fixable->getStrategyImplications();
4544 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
4545 PtrAssignmentGraph[Impl.first].insert(Impl.second);
4567 std::set<const VarDecl *> VisitedVarsDirected{};
4568 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4569 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
4571 std::queue<const VarDecl *> QueueDirected{};
4572 QueueDirected.push(Var);
4573 while (!QueueDirected.empty()) {
4574 const VarDecl *CurrentVar = QueueDirected.front();
4575 QueueDirected.pop();
4576 VisitedVarsDirected.insert(CurrentVar);
4577 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
4578 for (
const VarDecl *Adj : AdjacentNodes) {
4579 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
4580 QueueDirected.push(Adj);
4582 DependenciesMap[Var].insert(Adj);
4583 DependenciesMap[Adj].insert(Var);
4590 std::vector<VarGrpTy> Groups;
4594 std::map<const VarDecl *, unsigned> VarGrpMap;
4596 llvm::SetVector<const VarDecl *>
4601 std::set<const VarDecl *> VisitedVars{};
4602 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4603 if (VisitedVars.find(Var) == VisitedVars.end()) {
4604 VarGrpTy &VarGroup = Groups.emplace_back();
4605 std::queue<const VarDecl *> Queue{};
4608 while (!Queue.empty()) {
4609 const VarDecl *CurrentVar = Queue.front();
4611 VisitedVars.insert(CurrentVar);
4612 VarGroup.push_back(CurrentVar);
4613 auto AdjacentNodes = DependenciesMap[CurrentVar];
4614 for (
const VarDecl *Adj : AdjacentNodes) {
4615 if (VisitedVars.find(Adj) == VisitedVars.end()) {
4621 bool HasParm =
false;
4622 unsigned GrpIdx = Groups.size() - 1;
4624 for (
const VarDecl *
V : VarGroup) {
4625 VarGrpMap[
V] = GrpIdx;
4630 GrpsUnionForParms.insert_range(VarGroup);
4652 for (
auto I = FixablesForAllVars.
byVar.begin();
4653 I != FixablesForAllVars.
byVar.end();) {
4655 if (!VisitedVars.count((*I).first)) {
4657 I = FixablesForAllVars.
byVar.erase(I);
4665 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
4667 return FixablesForAllVars.
byVar.count(
V);
4674 FixItsForVariableGroup =
4676 Tracker, Handler, VarGrpMgr);
4678 for (
const auto &G : UnsafeOps.
noVar) {
4679 G->handleUnsafeOperation(Handler,
false,
4683 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
4684 auto FixItsIt = FixItsForVariableGroup.find(VD);
4686 FixItsIt != FixItsForVariableGroup.end()
4687 ? std::move(FixItsIt->second)
4690 for (
const auto &G : WarningGadgets) {
4691 G->handleUnsafeOperation(Handler,
true,
4699 bool EmitSuggestions) {
4708 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
4711 if (FD->isConsteval())
4716 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
4717 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
4722 if (FReDecl->isExternC()) {
4725 EmitSuggestions =
false;
4730 Stmts.push_back(FD->getBody());
4732 if (
const auto *ID = dyn_cast<CXXConstructorDecl>(D)) {
4734 Stmts.push_back(CI->getInit());
4738 Stmts.push_back(D->
getBody());
4741 assert(!Stmts.empty());
4743 FixableGadgetList FixableGadgets;
4744 WarningGadgetList WarningGadgets;
4745 DeclUseTracker Tracker;
4746 for (
Stmt *S : Stmts) {
4748 WarningGadgets, Tracker);
4750 applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
4751 std::move(Tracker), Handler, EmitSuggestions);
Defines the clang::ASTContext interface.
static Decl::Kind getKind(const Decl *D)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Preprocessor interface.
MatchFinder::MatchResult MatchResult
Defines the clang::SourceLocation class and associated facilities.
static QualType getPointeeType(const MemRegion *R)
C Language Family Type Representation.
static bool ignoreUnsafeLibcCall(const ASTContext &Ctx, const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
static void findStmtsInUnspecifiedLvalueContext(const Stmt *S, const llvm::function_ref< void(const Expr *)> OnResult)
static std::string getUserFillPlaceHolder(StringRef HintTextToUser="placeholder")
static FixItList fixVariableWithSpan(const VarDecl *VD, const DeclUseTracker &Tracker, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static std::optional< FixItList > fixUPCAddressofArraySubscriptWithSpan(const UnaryOperator *Node)
static bool ignoreUnsafeBufferInContainer(const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
static WarningGadgetSets groupWarningGadgetsByVar(const WarningGadgetList &AllUnsafeOperations)
static bool hasArrayType(const Expr &E)
static StringRef getEndOfLine()
static bool notInSafeBufferOptOut(const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
static std::optional< FixItList > FixVarInitializerWithSpan(const Expr *Init, ASTContext &Ctx, const StringRef UserFillPlaceHolder)
static std::optional< SourceLocation > getEndCharLoc(const NodeTy *Node, const SourceManager &SM, const LangOptions &LangOpts)
static FixItList fixVariableWithArray(const VarDecl *VD, const DeclUseTracker &Tracker, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static bool areEqualIntegralBinaryOperators(const BinaryOperator *E1, const Expr *E2_LHS, BinaryOperatorKind BOP, const Expr *E2_RHS, ASTContext &Ctx)
static bool hasPointerType(const Expr &E)
static std::string getSpanTypeText(StringRef EltTyText, std::optional< Qualifiers > Quals=std::nullopt)
static SourceRange getSourceRangeToTokenEnd(const Decl *D, const SourceManager &SM, const LangOptions &LangOpts)
static FixItList fixLocalVarDeclWithSpan(const VarDecl *D, ASTContext &Ctx, const StringRef UserFillPlaceHolder, UnsafeBufferUsageHandler &Handler)
static bool isSafeArraySubscript(const ArraySubscriptExpr &Node, const ASTContext &Ctx, const bool IgnoreStaticSizedArrays)
static std::optional< FixItList > createDataFixit(const ASTContext &Ctx, const DeclRefExpr *DRE)
static FixItList createFunctionOverloadsForParms(std::map< const VarDecl *, FixItList > &FixItsForVariable, const VariableGroupsManager &VarGrpMgr, const FunctionDecl *FD, const FixitStrategy &S, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static bool isNullTermPointer(const Expr *Ptr, ASTContext &Ctx)
static bool isSafeSpanTwoParamConstruct(const CXXConstructExpr &Node, ASTContext &Ctx)
static FixItList fixVarDeclWithArray(const VarDecl *D, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static FixItList fixVariable(const VarDecl *VD, FixitStrategy::Kind K, const Decl *D, const DeclUseTracker &Tracker, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static FixItList fixParamWithSpan(const ParmVarDecl *PVD, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static FixitStrategy getNaiveStrategy(llvm::iterator_range< VarDeclIterTy > UnsafeVars)
static std::optional< std::string > createSpanTypeForVarDecl(const VarDecl *VD, const ASTContext &Ctx)
static bool hasConflictingOverload(const FunctionDecl *FD)
static void findStmtsInUnspecifiedPointerContext(const Stmt *S, llvm::function_ref< void(const Stmt *)> InnerMatcher)
static bool isNonNegativeIntegerExpr(const Expr *Expr, const VarDecl *VD, const ASTContext &Ctx)
static bool overlapWithMacro(const FixItList &FixIts)
static void forEachDescendantStmt(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, FastMatcher &Matcher)
static bool hasUnsupportedSpecifiers(const VarDecl *VD, const SourceManager &SM)
static const Expr * tryConstantFoldConditionalExpr(const Expr *E, const ASTContext &Ctx)
static const Expr * getSubExprInAddressOfExpr(const Expr *E)
#define DEBUG_NOTE_DECL_FAIL(D, Msg)
static void applyGadgets(const Decl *D, FixableGadgetList FixableGadgets, WarningGadgetList WarningGadgets, DeclUseTracker Tracker, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
static bool areEqualIntegers(const Expr *E1, const Expr *E2, ASTContext &Ctx)
static void findGadgets(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, bool EmitSuggestions, FixableGadgetList &FixableGadgets, WarningGadgetList &WarningGadgets, DeclUseTracker &Tracker)
static std::map< const VarDecl *, FixItList > getFixIts(FixableGadgetSets &FixablesForAllVars, const FixitStrategy &S, ASTContext &Ctx, const Decl *D, const DeclUseTracker &Tracker, UnsafeBufferUsageHandler &Handler, const VariableGroupsManager &VarGrpMgr)
static const Expr * getSubExprInSizeOfExpr(const Expr *E)
static bool isPtrBufferSafe(const Expr *Ptr, const Expr *Size, ASTContext &Ctx)
static void forEachDescendantEvaluatedStmt(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, FastMatcher &Matcher)
static void findStmtsInUnspecifiedUntypedContext(const Stmt *S, llvm::function_ref< void(const Stmt *)> InnerMatcher)
static std::optional< FixItList > createOverloadsForFixedParams(const FixitStrategy &S, const FunctionDecl *FD, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static void eraseVarsForUnfixableGroupMates(std::map< const VarDecl *, FixItList > &FixItsForVariable, const VariableGroupsManager &VarGrpMgr)
static FixableGadgetSets groupFixablesByVar(FixableGadgetList &&AllFixableOperations)
static bool isParameterOf(const VarDecl *VD, const Decl *D)
#define SIZED_CONTAINER_OR_VIEW_LIST
static std::optional< StringRef > getFunNameText(const FunctionDecl *FD, const SourceManager &SM, const LangOptions &LangOpts)
__device__ __2f16 float __ockl_bool s
virtual std::optional< FixItList > getFixits(const FixitStrategy &s) const final
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
DerefSimplePtrArithFixableGadget(const MatchResult &Result)
SourceLocation getSourceLoc() const override
virtual DeclUseList getClaimedVarUseSites() const final
FixableGadgetMatcher(FixableGadgetList &FixableGadgets, DeclUseTracker &Tracker)
bool matches(const DynTypedNode &DynNode, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler) override
Represents the length modifier in a format string in scanf/printf.
bool TraverseCXXTypeidExpr(CXXTypeidExpr *Node) override
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc Node, bool TraverseQualifier) override
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc Node, bool TraverseQualifier) override
bool TraverseGenericSelectionExpr(GenericSelectionExpr *Node) override
MatchDescendantVisitor(ASTContext &Context, FastMatcher &Matcher, bool FindAll, bool IgnoreUnevaluatedContext, const UnsafeBufferUsageHandler &NewHandler)
bool TraverseDecl(Decl *Node) override
bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) override
bool findMatch(const DynTypedNode &DynNode)
bool TraverseCXXDefaultInitExpr(CXXDefaultInitExpr *Node) override
bool TraverseCXXNoexceptExpr(CXXNoexceptExpr *Node) override
bool TraverseStmt(Stmt *Node) override
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
SourceLocation getSourceLoc() const override
virtual DeclUseList getClaimedVarUseSites() const override
UPCPreIncrementGadget(const MatchResult &Result)
static bool classof(const Gadget *G)
static bool classof(const Gadget *G)
UUCAddAssignGadget(const MatchResult &Result)
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
virtual DeclUseList getClaimedVarUseSites() const override
SourceLocation getSourceLoc() const override
VariableGroupsManagerImpl(const std::vector< VarGrpTy > &Groups, const std::map< const VarDecl *, unsigned > &VarGrpMap, const llvm::SetVector< const VarDecl * > &GrpsUnionForParms)
VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm) const override
Returns the set of variables (including Var) that need to be fixed together in one step.
VarGrpRef getGroupOfParms() const override
Returns the non-empty group of variables that include parameters of the analyzing function,...
bool matches(const DynTypedNode &DynNode, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler) override
WarningGadgetMatcher(WarningGadgetList &WarningGadgets)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
const ConstantArrayType * getAsConstantArrayType(QualType T) const
DynTypedNodeList getParents(const NodeT &Node)
Forwards to get node parents from the ParentMapContext.
QualType getFILEType() const
Retrieve the C FILE type.
const LangOptions & getLangOpts() const
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Attr - This represents one attribute.
A builtin binary operation expression such as "x + y" or "x <= y".
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
Represents a call to a C++ constructor.
Expr * getArg(unsigned Arg)
Return the specified argument.
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
Represents a C++ base or member initializer.
A use of a default initializer in a constructor or in aggregate initialization.
Expr * getExpr()
Get the initialization expression that will be used.
Represents a static or instance method of a struct/union/class.
Represents a C++11 noexcept expression (C++ [expr.unary.noexcept]).
OverloadedOperatorKind getOperator() const
Returns the kind of overloaded operator that this expression refers to.
Represents a C++ struct/union/class.
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
A C++ typeid expression (C++ [expr.typeid]), which gets the type_info that corresponds to the supplie...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
static const char * getCastKindName(CastKind CK)
Represents a character-granular source range.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getEnd() const
bool isOne() const
isOne - Test whether the quantity equals one.
Represents a class template specialization, which refers to a class template with a given set of temp...
const TemplateArgumentList & getTemplateArgs() const
Retrieve the template arguments of the class template specialization.
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
bool isSingleResult() const
DeclContext * getParent()
getParent - Returns the containing DeclContext.
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
A reference to a declared variable, function, enum, etc.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
bool isSingleDecl() const
isSingleDecl - This method returns true if this DeclStmt refers to a single Decl.
const Decl * getSingleDecl() const
Decl - This represents one declaration (or definition), e.g.
bool isInStdNamespace() const
SourceLocation getEndLoc() const LLVM_READONLY
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
DeclContext * getDeclContext()
SourceLocation getBeginLoc() const LLVM_READONLY
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
SourceLocation getTypeSpecEndLoc() const
SourceLocation getBeginLoc() const LLVM_READONLY
NestedNameSpecifierLoc getQualifierLoc() const
Retrieve the nested-name-specifier (with source-location information) that qualifies the name of this...
NestedNameSpecifier getQualifier() const
Retrieve the nested-name-specifier that qualifies the name of this declaration, if it was present in ...
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
const DynTypedNode * begin() const
A dynamically typed AST node container.
const T * get() const
Retrieve the stored node as type T.
static DynTypedNode create(const T &Node)
Creates a DynTypedNode from Node.
virtual bool TraverseDecl(MaybeConst< Decl > *D)
bool ShouldVisitTemplateInstantiations
bool ShouldVisitImplicitCode
virtual bool TraverseStmt(MaybeConst< Stmt > *S)
This represents one expression.
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
bool isValueDependent() const
Determines whether the value of this expression depends on.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
NullPointerConstantValueDependence
Enumeration used to describe how isNullPointerConstant() should cope with value-dependent expressions...
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
static FixItHint CreateRemoval(CharSourceRange RemoveRange)
Create a code modification hint that removes the given source range.
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
Kind lookup(const VarDecl *VD) const
void set(const VarDecl *VD, Kind K)
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
unsigned getBuiltinID(bool ConsiderWrapperFunctions=false) const
Returns a value indicating whether this function corresponds to a builtin function.
param_iterator param_begin()
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
DeclarationNameInfo getNameInfo() const
Represents a C11 generic selection.
Expr * getResultExpr()
Return the result expression of this controlling expression.
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
A simple pair of identifier info and location.
static IntegerLiteral * Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l)
Returns a new integer literal with value 'V' and type 'type'.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static std::optional< Token > findNextToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts, bool IncludeComments=false)
Finds the token that comes right after the given location.
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)
Computes the source location just past the end of the token at this source location.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
SourceLocation getBeginLoc() const
Retrieve the location of the beginning of this nested-name-specifier.
A single parameter index whose accessors require each use to make explicit the parameter index encodi...
bool isValid() const
Is this parameter index valid?
unsigned getASTIndex() const
Get the parameter index as it would normally be encoded at the AST level of representation: zero-orig...
Represents a parameter to a function.
bool hasDefaultArg() const
Determines whether this parameter has a default argument, either parsed or not.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
PointerType - C99 6.7.5.1 - Pointer Declarators.
A (possibly-)qualified type.
bool hasQualifiers() const
Determine whether this type has any qualifiers.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
QualType getCanonicalType() const
bool isConstQualified() const
Determine whether this type is const-qualified.
std::string getAsString() const
Represents a struct/union/class.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
Stmt - This represents one statement.
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const char * getStmtClassName() const
SourceLocation getBeginLoc() const LLVM_READONLY
Exposes information about the current target.
A template argument list.
unsigned size() const
Retrieve the number of template arguments in this template argument list.
Represents a template argument.
QualType getAsType() const
Retrieve the type for a type template argument.
@ Type
The template argument is a type.
ArgKind getKind() const
Return the kind of stored template argument.
The base class of the type hierarchy.
bool isConstantSizeType() const
Return true if this is not a variable sized type, according to the rules of C99 6....
bool isPointerType() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
const T * castAs() const
Member-template castAs<specific type>.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isAnyCharacterType() const
Determine whether this type is any of the built-in character types.
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
bool isAnyPointerType() const
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
static bool isIncrementOp(Opcode Op)
SourceLocation getBeginLoc() const LLVM_READONLY
static bool isDecrementOp(Opcode Op)
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
The interface that lets the caller handle unsafe buffer usage analysis results by overriding this cla...
virtual void handleUnsafeUniquePtrArrayAccess(const DynTypedNode &Node, bool IsRelatedToDecl, ASTContext &Ctx)=0
void addDebugNoteForVar(const VarDecl *VD, SourceLocation Loc, std::string Text)
virtual std::string getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, StringRef WSSuffix="") const =0
virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const =0
virtual bool ignoreUnsafeBufferInContainer(const SourceLocation &Loc) const =0
virtual void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation over raw pointers is found.
virtual void handleUnsafeVariableGroup(const VarDecl *Variable, const VariableGroupsManager &VarGrpMgr, FixItList &&Fixes, const Decl *D, const FixitStrategy &VarTargetTypes)=0
Invoked when a fix is suggested against a variable.
virtual void handleUnsafeOperationInContainer(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation with a std container is found.
virtual bool ignoreUnsafeBufferInStaticSizedArray(const SourceLocation &Loc) const =0
virtual bool ignoreUnsafeBufferInLibcCall(const SourceLocation &Loc) const =0
virtual void handleUnsafeLibcCall(const CallExpr *Call, unsigned PrintfInfo, ASTContext &Ctx, const Expr *UnsafeArg=nullptr)=0
Invoked when a call to an unsafe libc function is found.
Represents a variable declaration or definition.
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
VarDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
bool isInlineSpecified() const
bool hasConstantInitialization() const
Determine whether this variable has constant initialization.
const Expr * getInit() const
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
const Expr * getAnyInitializer() const
Get the initializer for this variable, no matter which declaration it is attached to.
VariableGroupsManager()=default
virtual VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm=nullptr) const =0
Returns the set of variables (including Var) that need to be fixed together in one step.
virtual VarGrpRef getGroupOfParms() const =0
Returns the non-empty group of variables that include parameters of the analyzing function,...
unsigned getArgIndex() const
bool hasDataArgument() const
HowSpecified getHowSpecified() const
unsigned getConstantAmount() const
const OptionalAmount & getPrecision() const
const PrintfConversionSpecifier & getConversionSpecifier() const
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
void matchEachArgumentWithParamType(const CallExpr &Node, llvm::function_ref< void(QualType, const Expr *)> OnParamAndArg)
bool anyConflict(const llvm::SmallVectorImpl< FixItHint > &FixIts, const SourceManager &SM)
bool matches(const til::SExpr *E1, const til::SExpr *E2)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
SourceLocation getVarDeclIdentifierLoc(const DeclaratorDecl *VD)
static bool classof(const OMPClause *T)
std::vector< const VarDecl * > VarGrpTy
std::optional< StringRef > getExprText(const Expr *E, const SourceManager &SM, const LangOptions &LangOpts)
@ Result
The result type of a method or function.
const FunctionProtoType * T
std::optional< std::string > getPointeeTypeText(const DeclaratorDecl *VD, const SourceManager &SM, const LangOptions &LangOpts, std::optional< Qualifiers > *QualifiersToAppend)
std::optional< StringRef > getRangeText(SourceRange SR, const SourceManager &SM, const LangOptions &LangOpts)
std::optional< StringRef > getVarDeclIdentifierText(const DeclaratorDecl *VD, const SourceManager &SM, const LangOptions &LangOpts)
std::optional< SourceLocation > getPastLoc(const NodeTy *Node, const SourceManager &SM, const LangOptions &LangOpts)
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
std::set< const Expr * > findUnsafePointers(const FunctionDecl *FD)
ArrayRef< const VarDecl * > VarGrpRef
static bool hasUnsafePrintfStringArg(const CallExpr &Node, ASTContext &Ctx, MatchResult &Result, llvm::StringRef Tag)
static bool isPredefinedUnsafeLibcFunc(const FunctionDecl &Node)
static bool hasUnsafeSnprintfBuffer(const CallExpr &Node, ASTContext &Ctx)
static bool isUnsafeVaListPrintfFunc(const FunctionDecl &Node)
static bool isUnsafeSprintfFunc(const FunctionDecl &Node)
static bool hasUnsafeFormatOrSArg(ASTContext &Ctx, const CallExpr *Call, const Expr *&UnsafeArg, const unsigned FmtIdx, std::optional< const unsigned > FmtArgIdx=std::nullopt, bool isKprintf=false)
static bool isUnsafeMemset(const CallExpr &Node, ASTContext &Ctx)
static bool isNormalPrintfFunc(const FunctionDecl &Node)
bool operator()(const NodeTy *N1, const NodeTy *N2) const
std::map< const VarDecl *, std::set< const FixableGadget * >, CompareNode< VarDecl > > byVar
std::map< const VarDecl *, std::set< const WarningGadget * >, CompareNode< VarDecl > > byVar
llvm::SmallVector< const WarningGadget *, 16 > noVar
SourceLocation getBeginLoc() const
getBeginLoc - Retrieve the location of the first token.
SourceLocation getEndLoc() const LLVM_READONLY
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.
const BoundNodes Nodes
Contains the nodes bound on the current match.
StringRef matchLibcName(StringRef Name)
StringRef matchName(StringRef FunName, bool isBuiltin)
StringRef matchLibcNameOrBuiltinChk(StringRef Name)