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(),
470 if (
const auto *UO = dyn_cast<UnaryOperator>(Ptr)) {
471 if (UO->
getOpcode() != UnaryOperator::Opcode::UO_AddrOf)
477 if (
const auto *CE = dyn_cast<CallExpr>(Ptr)) {
482 return CE->getArg(0)->IgnoreParenImpCasts();
492 const auto *SizeOfExpr =
494 if (!SizeOfExpr || SizeOfExpr->getKind() != UETT_SizeOf)
496 if (SizeOfExpr->isArgumentType())
498 return SizeOfExpr->getArgumentExpr()->IgnoreParenImpCasts();
519 dyn_cast<CXXMemberCallExpr>(Size->IgnoreParenImpCasts())) {
520 auto *DREOfPtr = dyn_cast<DeclRefExpr>(
521 MCEPtr->getImplicitObjectArgument()->IgnoreParenImpCasts());
522 auto *DREOfSize = dyn_cast<DeclRefExpr>(
523 MCESize->getImplicitObjectArgument()->IgnoreParenImpCasts());
525 if (!DREOfPtr || !DREOfSize)
529 if (DREOfPtr->getDecl() != DREOfSize->getDecl())
531 if (MCEPtr->getMethodDecl()->getName() !=
"data")
534 if (!MCEPtr->getRecordDecl()->isInStdNamespace())
537 auto *ObjII = MCEPtr->getRecordDecl()->getIdentifier();
544 if (!((AcceptSizeBytes &&
545 MCESize->getMethodDecl()->getName() ==
"size_bytes") ||
550 MCESize->getMethodDecl()->getName() ==
"size"))
560 if (Size->EvaluateAsInt(ER, Ctx)) {
566 return llvm::APSInt::compareValues(
567 SizeInt, llvm::APSInt(CAT->getSize(),
true)) == 0;
601 "expecting a two-parameter std::span constructor");
604 auto HaveEqualConstantValues = [&Ctx](
const Expr *E0,
const Expr *E1) {
606 if (
auto E1CV = E1->getIntegerConstantExpr(Ctx)) {
607 return llvm::APSInt::compareValues(*E0CV, *E1CV) == 0;
611 auto AreSameDRE = [](
const Expr *E0,
const Expr *E1) {
612 if (
auto *DRE0 = dyn_cast<DeclRefExpr>(E0))
613 if (
auto *DRE1 = dyn_cast<DeclRefExpr>(E1)) {
614 return DRE0->getDecl() == DRE1->getDecl();
620 if (Arg1CV && Arg1CV->isZero())
626 case Stmt::CXXNewExprClass:
629 return AreSameDRE((*Size)->IgnoreImplicit(), Arg1) ||
630 HaveEqualConstantValues(*Size, Arg1);
635 return Arg1CV && Arg1CV->isOne();
643 if (
auto CCast = dyn_cast<CStyleCastExpr>(Arg0)) {
644 if (!CCast->getType()->isPointerType())
652 if (
const auto *
Call = dyn_cast<CallExpr>(CCast->getSubExpr())) {
654 if (
auto *AllocAttr = FD->getAttr<AllocSizeAttr>()) {
655 const Expr *EleSizeExpr =
656 Call->getArg(AllocAttr->getElemSizeParam().getASTIndex());
658 ParamIdx NumElemIdx = AllocAttr->getNumElemsParam();
665 if (
auto BO = dyn_cast<BinaryOperator>(Arg1))
672 auto IsMethodCallToSizedObject = [](
const Stmt *Node, StringRef MethodName) {
673 if (
const auto *MC = dyn_cast<CXXMemberCallExpr>(Node)) {
674 const auto *MD = MC->getMethodDecl();
675 const auto *RD = MC->getRecordDecl();
678 if (
auto *II = RD->getDeclName().getAsIdentifierInfo();
679 II && RD->isInStdNamespace())
682 MD->getName() == MethodName;
687 if (IsMethodCallToSizedObject(Arg0,
"begin") &&
688 IsMethodCallToSizedObject(Arg1,
"end"))
692 ->getImplicitObjectArgument()
693 ->IgnoreParenImpCasts(),
695 ->getImplicitObjectArgument()
696 ->IgnoreParenImpCasts());
704 const bool IgnoreStaticSizedArrays) {
713 if (
const auto *CATy =
714 dyn_cast<ConstantArrayType>(Node.
getBase()
718 limit = CATy->getLimitedSize();
719 }
else if (
const auto *SLiteral = dyn_cast<clang::StringLiteral>(
721 limit = SLiteral->getLength() + 1;
726 if (IgnoreStaticSizedArrays) {
736 llvm::APSInt ArrIdx = EVResult.
Val.
getInt();
739 if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit)
741 }
else if (
const auto *BE = dyn_cast<BinaryOperator>(IndexExpr)) {
744 if (BE->getOpcode() != BO_And && BE->getOpcode() != BO_Rem)
747 const Expr *LHS = BE->getLHS();
748 const Expr *RHS = BE->getRHS();
750 if (BE->getOpcode() == BO_Rem) {
757 llvm::APSInt result = EVResult.
Val.
getInt();
758 if (result.isNonNegative() && result.getLimitedValue() <= limit)
769 llvm::APSInt result = EVResult.
Val.
getInt();
770 if (result.isNonNegative() && result.getLimitedValue() < limit)
784 if (
const auto *CE = dyn_cast<ConditionalOperator>(E)) {
786 const auto *
Cond = CE->getCond();
788 if (!
Cond->isValueDependent() &&
789 Cond->EvaluateAsBooleanCondition(CondEval, Ctx))
790 return CondEval ? CE->getLHS() : CE->getRHS();
800 if (
const auto *DefaultArgE = dyn_cast<CXXDefaultArgExpr>(Ptr))
808 if (
const auto *CondE = dyn_cast<ConditionalOperator>(Ptr)) {
817 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Ptr)) {
827 static const llvm::StringSet<> NullTermFunctions = {
"strerror"};
828 if (
auto *CE = dyn_cast<CallExpr>(Ptr)) {
851 if (Name.ends_with(
"_s"))
852 return Name.drop_back(2 );
859 if (Name.starts_with(
"__") && Name.ends_with(
"_chk"))
861 Name.drop_front(2).drop_back(4) );
865static StringRef
matchName(StringRef FunName,
bool isBuiltin) {
867 if (isBuiltin && FunName.starts_with(
"__builtin_"))
871 FunName.drop_front(10 ));
873 if (FunName.starts_with(
"__asan_"))
890 const Expr *&UnsafeArg,
const unsigned FmtIdx,
891 std::optional<const unsigned> FmtArgIdx = std::nullopt,
892 bool isKprintf =
false) {
893 class StringFormatStringHandler
897 const Expr *&UnsafeArg;
913 unsigned PArgIdx = Precision.
getArgIndex() + FmtArgIdx;
915 if (PArgIdx < Call->getNumArgs()) {
916 const Expr *PArg =
Call->getArg(PArgIdx);
919 if (
auto *CE = dyn_cast<CastExpr>(PArg);
920 CE && CE->getType()->isSignedIntegerType())
921 PArg = CE->getSubExpr();
926 analyze_printf::OptionalAmount::HowSpecified::Constant) {
928 llvm::APSInt PArgVal = llvm::APSInt(
938 StringFormatStringHandler(
const CallExpr *
Call,
unsigned FmtArgIdx,
940 :
Call(
Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx),
941 UnsafeArgSet(
false) {}
944 const char *startSpecifier,
945 unsigned specifierLen,
953 if (ArgIdx >=
Call->getNumArgs())
957 const Expr *Arg =
Call->getArg(ArgIdx);
967 bool IsArgTypeValid =
970 ?
ArgType->getPointeeType()->isWideCharType()
971 :
ArgType->getPointeeType()->isCharType());
974 Precision && IsArgTypeValid)
978 UnsafeArg =
Call->getArg(ArgIdx);
983 bool isUnsafeArgSet() {
return UnsafeArgSet; }
986 const Expr *Fmt =
Call->getArg(FmtIdx);
987 unsigned FmtArgStartingIdx =
988 FmtArgIdx.has_value() ?
static_cast<unsigned>(*FmtArgIdx) : FmtIdx + 1;
991 if (SL->getCharByteWidth() == 1) {
992 StringRef FmtStr = SL->getString();
993 StringFormatStringHandler Handler(
Call, FmtArgStartingIdx, UnsafeArg,
997 Handler, FmtStr.begin(), FmtStr.end(), Ctx.
getLangOpts(),
999 Handler.isUnsafeArgSet();
1002 if (
auto FmtStr = SL->tryEvaluateString(Ctx)) {
1003 StringFormatStringHandler Handler(
Call, FmtArgStartingIdx, UnsafeArg,
1006 Handler, FmtStr->data(), FmtStr->data() + FmtStr->size(),
1008 Handler.isUnsafeArgSet();
1014 return llvm::any_of(
1015 llvm::make_range(
Call->arg_begin() + FmtIdx,
Call->arg_end()),
1016 [&UnsafeArg, &Ctx](
const Expr *Arg) ->
bool {
1017 if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg, Ctx)) {
1035 static std::unique_ptr<std::set<StringRef>> PredefinedNames =
nullptr;
1036 if (!PredefinedNames)
1038 std::make_unique<std::set<StringRef>, std::set<StringRef>>({
1117 if (PredefinedNames->find(Name) != PredefinedNames->end())
1120 std::string NameWCS = Name.str();
1121 size_t WcsPos = NameWCS.find(
"wcs");
1123 while (WcsPos != std::string::npos) {
1124 NameWCS[WcsPos++] =
's';
1125 NameWCS[WcsPos++] =
't';
1126 NameWCS[WcsPos++] =
'r';
1127 WcsPos = NameWCS.find(
"wcs", WcsPos);
1129 if (PredefinedNames->find(NameWCS) != PredefinedNames->end())
1133 return Name.ends_with(
"scanf");
1141 assert(FD &&
"It should have been checked that FD is non-null.");
1148 if (Name !=
"memset")
1160 const auto *AddressOfVar = dyn_cast_if_present<DeclRefExpr>(
1165 const auto *SizeOfVar =
1170 return AddressOfVar->getDecl() != SizeOfVar->getDecl();
1184 return Name.starts_with(
"v") && Name.ends_with(
"printf");
1197 return Name ==
"sprintf" || Name ==
"swprintf";
1211 if (!Name.ends_with(
"printf"))
1214 StringRef Prefix = Name.drop_back(6);
1216 if (Prefix.ends_with(
"w"))
1217 Prefix = Prefix.drop_back(1);
1219 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
1227 MatchResult &Result, llvm::StringRef Tag) {
1231 assert(FD &&
"It should have been checked that FD is non-null.");
1249 const Expr *UnsafeArg;
1260 bool isKprintf =
false;
1261 const Expr *UnsafeArg;
1264 isKprintf = II->getName() ==
"kprintf";
1266 std::nullopt, isKprintf)) {
1279 const Expr *UnsafeArg;
1290 for (
const auto *Arg : Node.
arguments())
1305 assert(FD &&
"It should have been checked that FD is non-null.");
1320 !Size->getType()->isUnsignedIntegerType())
1349#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1352 Gadget(Kind K) : K(K) {}
1354 Kind
getKind()
const {
return K; }
1357 StringRef getDebugName()
const {
1362#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1364 llvm_unreachable(
"Unhandled Gadget::Kind enum");
1368 virtual bool isWarningGadget()
const = 0;
1371 virtual SourceLocation getSourceLoc()
const = 0;
1376 virtual DeclUseList getClaimedVarUseSites()
const = 0;
1378 virtual ~Gadget() =
default;
1386class WarningGadget :
public Gadget {
1388 WarningGadget(Kind K) : Gadget(K) {}
1390 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1391 bool isWarningGadget() const final {
return true; }
1393 virtual void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1394 bool IsRelatedToDecl,
1395 ASTContext &Ctx)
const = 0;
1397 virtual SmallVector<const Expr *, 1> getUnsafePtrs()
const = 0;
1404class FixableGadget :
public Gadget {
1406 FixableGadget(Kind K) : Gadget(K) {}
1408 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1409 bool isWarningGadget() const final {
return false; }
1414 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1415 return std::nullopt;
1424 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1425 getStrategyImplications()
const {
1426 return std::nullopt;
1430static bool isSupportedVariable(
const DeclRefExpr &Node) {
1442 dyn_cast<ClassTemplateSpecializationDecl>(
RecordDecl);
1443 if (!class_template_specialization_decl)
1448 if (template_args.
size() == 0)
1459class UniquePtrArrayAccessGadget :
public WarningGadget {
1461 static constexpr const char *
const AccessorTag =
"unique_ptr_array_access";
1462 const CXXOperatorCallExpr *AccessorExpr;
1466 : WarningGadget(
Kind::UniquePtrArrayAccess),
1467 AccessorExpr(
Result.getNodeAs<CXXOperatorCallExpr>(AccessorTag)) {
1468 assert(AccessorExpr &&
1469 "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr");
1472 static bool classof(
const Gadget *G) {
1473 return G->getKind() == Kind::UniquePtrArrayAccess;
1476 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1479 const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(S);
1480 if (!OpCall || OpCall->
getOperator() != OO_Subscript)
1487 const CXXMethodDecl *
Method =
1492 if (
Method->getOverloadedOperator() != OO_Subscript)
1496 if (!isUniquePtrArray(RecordDecl))
1499 const Expr *IndexExpr = OpCall->
getArg(1);
1500 clang::Expr::EvalResult Eval;
1506 Result.addNode(AccessorTag, DynTypedNode::create(*OpCall));
1509 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1510 bool IsRelatedToDecl,
1511 ASTContext &Ctx)
const override {
1513 DynTypedNode::create(*AccessorExpr), IsRelatedToDecl, Ctx);
1516 SourceLocation getSourceLoc()
const override {
1518 return AccessorExpr->getOperatorLoc();
1519 return SourceLocation();
1522 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1523 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1526using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1527using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1531class IncrementGadget :
public WarningGadget {
1532 static constexpr const char *
const OpTag =
"op";
1533 const UnaryOperator *Op;
1537 : WarningGadget(
Kind::Increment),
1538 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1540 static bool classof(
const Gadget *G) {
1541 return G->getKind() == Kind::Increment;
1544 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1546 const auto *UO = dyn_cast<UnaryOperator>(S);
1551 Result.addNode(OpTag, DynTypedNode::create(*UO));
1555 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1556 bool IsRelatedToDecl,
1557 ASTContext &Ctx)
const override {
1560 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1562 DeclUseList getClaimedVarUseSites()
const override {
1563 SmallVector<const DeclRefExpr *, 2> Uses;
1564 if (
const auto *DRE =
1565 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1566 Uses.push_back(DRE);
1569 return std::move(Uses);
1572 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1573 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1579class DecrementGadget :
public WarningGadget {
1580 static constexpr const char *
const OpTag =
"op";
1581 const UnaryOperator *Op;
1585 : WarningGadget(
Kind::Decrement),
1586 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1588 static bool classof(
const Gadget *G) {
1589 return G->getKind() == Kind::Decrement;
1592 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1594 const auto *UO = dyn_cast<UnaryOperator>(S);
1599 Result.addNode(OpTag, DynTypedNode::create(*UO));
1603 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1604 bool IsRelatedToDecl,
1605 ASTContext &Ctx)
const override {
1608 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1610 DeclUseList getClaimedVarUseSites()
const override {
1611 if (
const auto *DRE =
1612 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1619 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1620 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1626class ArraySubscriptGadget :
public WarningGadget {
1627 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1628 const ArraySubscriptExpr *ASE;
1633 ASE(
Result.getNodeAs<ArraySubscriptExpr>(ArraySubscrTag)) {}
1635 static bool classof(
const Gadget *G) {
1636 return G->getKind() == Kind::ArraySubscript;
1639 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1640 const UnsafeBufferUsageHandler *Handler,
1642 const auto *ASE = dyn_cast<ArraySubscriptExpr>(S);
1645 const auto *
const Base = ASE->getBase()->IgnoreParenImpCasts();
1648 const auto *Idx = dyn_cast<IntegerLiteral>(ASE->getIdx());
1649 bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
1656 Result.addNode(ArraySubscrTag, DynTypedNode::create(*ASE));
1660 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1661 bool IsRelatedToDecl,
1662 ASTContext &Ctx)
const override {
1665 SourceLocation getSourceLoc()
const override {
return ASE->getBeginLoc(); }
1667 DeclUseList getClaimedVarUseSites()
const override {
1668 if (
const auto *DRE =
1669 dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
1676 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1677 return {ASE->getBase()->IgnoreParenImpCasts()};
1685class PointerArithmeticGadget :
public WarningGadget {
1686 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1687 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1688 const BinaryOperator *PA;
1693 : WarningGadget(
Kind::PointerArithmetic),
1694 PA(
Result.getNodeAs<BinaryOperator>(PointerArithmeticTag)),
1695 Ptr(
Result.getNodeAs<Expr>(PointerArithmeticPointerTag)) {}
1697 static bool classof(
const Gadget *G) {
1698 return G->getKind() == Kind::PointerArithmetic;
1701 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1703 const auto *BO = dyn_cast<BinaryOperator>(S);
1706 const auto *LHS = BO->
getLHS();
1707 const auto *RHS = BO->
getRHS();
1712 RHS->getType()->isEnumeralType())) {
1713 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*LHS));
1714 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1720 (LHS->getType()->isIntegerType() || LHS->getType()->isEnumeralType())) {
1721 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*RHS));
1722 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1728 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1729 bool IsRelatedToDecl,
1730 ASTContext &Ctx)
const override {
1733 SourceLocation getSourceLoc()
const override {
return PA->getBeginLoc(); }
1735 DeclUseList getClaimedVarUseSites()
const override {
1736 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts())) {
1743 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1744 return {Ptr->IgnoreParenImpCasts()};
1751class SpanTwoParamConstructorGadget :
public WarningGadget {
1752 static constexpr const char *
const SpanTwoParamConstructorTag =
1753 "spanTwoParamConstructor";
1754 const CXXConstructExpr *Ctor;
1758 : WarningGadget(
Kind::SpanTwoParamConstructor),
1759 Ctor(
Result.getNodeAs<CXXConstructExpr>(SpanTwoParamConstructorTag)) {}
1761 static bool classof(
const Gadget *G) {
1762 return G->getKind() == Kind::SpanTwoParamConstructor;
1766 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1769 const auto *CDecl = CE->getConstructor();
1770 const auto *CRecordDecl = CDecl->getParent();
1771 auto HasTwoParamSpanCtorDecl =
1772 CRecordDecl->isInStdNamespace() &&
1773 CDecl->getDeclName().getAsString() ==
"span" && CE->getNumArgs() == 2;
1776 Result.addNode(SpanTwoParamConstructorTag, DynTypedNode::create(*CE));
1780 static bool matches(
const Stmt *S, ASTContext &Ctx,
1781 const UnsafeBufferUsageHandler *Handler,
1788 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1789 bool IsRelatedToDecl,
1790 ASTContext &Ctx)
const override {
1793 SourceLocation getSourceLoc()
const override {
return Ctor->getBeginLoc(); }
1795 DeclUseList getClaimedVarUseSites()
const override {
1798 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->getArg(0))) {
1805 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1812class PointerInitGadget :
public FixableGadget {
1814 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1815 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1816 const VarDecl *PtrInitLHS;
1817 const DeclRefExpr *PtrInitRHS;
1821 : FixableGadget(
Kind::PointerInit),
1822 PtrInitLHS(
Result.getNodeAs<VarDecl>(PointerInitLHSTag)),
1823 PtrInitRHS(
Result.getNodeAs<DeclRefExpr>(PointerInitRHSTag)) {}
1825 static bool classof(
const Gadget *G) {
1826 return G->getKind() == Kind::PointerInit;
1829 static bool matches(
const Stmt *S,
1830 llvm::SmallVectorImpl<MatchResult> &Results) {
1831 const DeclStmt *DS = dyn_cast<DeclStmt>(S);
1840 const auto *DRE = dyn_cast<DeclRefExpr>(
Init->IgnoreImpCasts());
1841 if (!DRE || !
hasPointerType(*DRE) || !isSupportedVariable(*DRE)) {
1845 R.addNode(PointerInitLHSTag, DynTypedNode::create(*VD));
1846 R.addNode(PointerInitRHSTag, DynTypedNode::create(*DRE));
1847 Results.emplace_back(std::move(R));
1851 virtual std::optional<FixItList>
1852 getFixits(
const FixitStrategy &S)
const override;
1853 SourceLocation getSourceLoc()
const override {
1854 return PtrInitRHS->getBeginLoc();
1857 virtual DeclUseList getClaimedVarUseSites()
const override {
1858 return DeclUseList{PtrInitRHS};
1861 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1862 getStrategyImplications()
const override {
1863 return std::make_pair(PtrInitLHS,
cast<VarDecl>(PtrInitRHS->getDecl()));
1872class PtrToPtrAssignmentGadget :
public FixableGadget {
1874 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1875 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1876 const DeclRefExpr *PtrLHS;
1877 const DeclRefExpr *PtrRHS;
1881 : FixableGadget(
Kind::PtrToPtrAssignment),
1882 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1883 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1885 static bool classof(
const Gadget *G) {
1886 return G->getKind() == Kind::PtrToPtrAssignment;
1889 static bool matches(
const Stmt *S,
1890 llvm::SmallVectorImpl<MatchResult> &Results) {
1891 size_t SizeBefore = Results.size();
1893 const auto *BO = dyn_cast<BinaryOperator>(S);
1894 if (!BO || BO->
getOpcode() != BO_Assign)
1897 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1899 !isSupportedVariable(*RHSRef)) {
1902 const auto *LHS = BO->
getLHS();
1903 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1905 !isSupportedVariable(*LHSRef)) {
1909 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1910 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1911 Results.emplace_back(std::move(R));
1913 return SizeBefore != Results.size();
1916 virtual std::optional<FixItList>
1917 getFixits(
const FixitStrategy &S)
const override;
1918 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1920 virtual DeclUseList getClaimedVarUseSites()
const override {
1921 return DeclUseList{PtrLHS, PtrRHS};
1924 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1925 getStrategyImplications()
const override {
1936class CArrayToPtrAssignmentGadget :
public FixableGadget {
1938 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1939 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1940 const DeclRefExpr *PtrLHS;
1941 const DeclRefExpr *PtrRHS;
1945 : FixableGadget(
Kind::CArrayToPtrAssignment),
1946 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1947 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1949 static bool classof(
const Gadget *G) {
1950 return G->getKind() == Kind::CArrayToPtrAssignment;
1953 static bool matches(
const Stmt *S,
1954 llvm::SmallVectorImpl<MatchResult> &Results) {
1955 size_t SizeBefore = Results.size();
1957 const auto *BO = dyn_cast<BinaryOperator>(S);
1958 if (!BO || BO->
getOpcode() != BO_Assign)
1961 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1964 !isSupportedVariable(*RHSRef)) {
1967 const auto *LHS = BO->
getLHS();
1968 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1970 !isSupportedVariable(*LHSRef)) {
1974 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1975 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1976 Results.emplace_back(std::move(R));
1978 return SizeBefore != Results.size();
1981 virtual std::optional<FixItList>
1982 getFixits(
const FixitStrategy &S)
const override;
1983 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1985 virtual DeclUseList getClaimedVarUseSites()
const override {
1986 return DeclUseList{PtrLHS, PtrRHS};
1989 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1990 getStrategyImplications()
const override {
1997class UnsafeBufferUsageAttrGadget :
public WarningGadget {
1998 constexpr static const char *
const OpTag =
"attr_expr";
2003 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
2004 Op(
Result.getNodeAs<Expr>(OpTag)) {}
2006 static bool classof(
const Gadget *G) {
2007 return G->getKind() == Kind::UnsafeBufferUsageAttr;
2010 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2012 if (
auto *CE = dyn_cast<CallExpr>(S)) {
2013 if (CE->getDirectCallee() &&
2014 CE->getDirectCallee()->hasAttr<UnsafeBufferUsageAttr>()) {
2015 Result.addNode(OpTag, DynTypedNode::create(*CE));
2019 if (
auto *ME = dyn_cast<MemberExpr>(S)) {
2022 if (ME->getMemberDecl()->hasAttr<UnsafeBufferUsageAttr>()) {
2023 Result.addNode(OpTag, DynTypedNode::create(*ME));
2030 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2031 bool IsRelatedToDecl,
2032 ASTContext &Ctx)
const override {
2035 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2037 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2039 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2045class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
2046 constexpr static const char *
const OpTag =
"cxx_construct_expr";
2047 const CXXConstructExpr *Op;
2051 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
2052 Op(
Result.getNodeAs<CXXConstructExpr>(OpTag)) {}
2054 static bool classof(
const Gadget *G) {
2055 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
2059 const auto *CE = dyn_cast<CXXConstructExpr>(S);
2060 if (!CE || !CE->getConstructor()->hasAttr<UnsafeBufferUsageAttr>())
2064 if (SpanTwoParamConstructorGadget::matches(CE, Ctx, Tmp))
2066 Result.addNode(OpTag, DynTypedNode::create(*CE));
2070 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2071 bool IsRelatedToDecl,
2072 ASTContext &Ctx)
const override {
2075 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2077 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2079 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2086class DataInvocationGadget :
public WarningGadget {
2087 constexpr static const char *
const OpTag =
"data_invocation_expr";
2088 const ExplicitCastExpr *Op;
2092 : WarningGadget(
Kind::DataInvocation),
2093 Op(
Result.getNodeAs<ExplicitCastExpr>(OpTag)) {}
2095 static bool classof(
const Gadget *G) {
2096 return G->getKind() == Kind::DataInvocation;
2099 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2101 auto *CE = dyn_cast<ExplicitCastExpr>(S);
2104 for (
auto *Child : CE->children()) {
2105 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Child);
2106 MCE && isDataFunction(MCE)) {
2107 Result.addNode(OpTag, DynTypedNode::create(*CE));
2110 if (
auto *
Paren = dyn_cast<ParenExpr>(Child)) {
2111 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(
Paren->getSubExpr());
2112 MCE && isDataFunction(MCE)) {
2113 Result.addNode(OpTag, DynTypedNode::create(*CE));
2121 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2122 bool IsRelatedToDecl,
2123 ASTContext &Ctx)
const override {
2126 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2128 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2131 static bool isDataFunction(
const CXXMemberCallExpr *call) {
2138 if (method->getNameAsString() ==
"data" &&
2139 method->getParent()->isInStdNamespace() &&
2140 llvm::is_contained({SIZED_CONTAINER_OR_VIEW_LIST},
2141 method->getParent()->getName()))
2146 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2149class UnsafeLibcFunctionCallGadget :
public WarningGadget {
2150 const CallExpr *
const Call;
2151 const Expr *UnsafeArg =
nullptr;
2152 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
2154 constexpr static const char *
const UnsafeSprintfTag =
2155 "UnsafeLibcFunctionCall_sprintf";
2156 constexpr static const char *
const UnsafeSizedByTag =
2157 "UnsafeLibcFunctionCall_sized_by";
2158 constexpr static const char *
const UnsafeStringTag =
2159 "UnsafeLibcFunctionCall_string";
2160 constexpr static const char *
const UnsafeVaListTag =
2161 "UnsafeLibcFunctionCall_va_list";
2175 } WarnedFunKind = OTHERS;
2178 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2179 Call(
Result.getNodeAs<CallExpr>(Tag)) {
2180 if (
Result.getNodeAs<Decl>(UnsafeSprintfTag))
2181 WarnedFunKind = SPRINTF;
2182 else if (
auto *E =
Result.getNodeAs<Expr>(UnsafeStringTag)) {
2183 WarnedFunKind = STRING;
2185 }
else if (
Result.getNodeAs<CallExpr>(UnsafeSizedByTag)) {
2186 WarnedFunKind = SIZED_BY;
2187 UnsafeArg = Call->getArg(0);
2188 }
else if (
Result.getNodeAs<Decl>(UnsafeVaListTag))
2189 WarnedFunKind = VA_LIST;
2192 static bool matches(
const Stmt *S, ASTContext &Ctx,
2193 const UnsafeBufferUsageHandler *Handler,
2197 const auto *CE = dyn_cast<CallExpr>(S);
2200 const auto *FD = CE->getDirectCallee();
2204 const bool IsGlobalAndNotInAnyNamespace =
2205 FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
2209 if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
2216 const bool isSingleStringLiteralArg =
2217 CE->getNumArgs() == 1 &&
2219 if (!isSingleStringLiteralArg) {
2222 Result.addNode(Tag, DynTypedNode::create(*CE));
2226 Result.addNode(Tag, DynTypedNode::create(*CE));
2230 Result.addNode(Tag, DynTypedNode::create(*CE));
2231 Result.addNode(UnsafeVaListTag, DynTypedNode::create(*FD));
2235 Result.addNode(Tag, DynTypedNode::create(*CE));
2236 Result.addNode(UnsafeSprintfTag, DynTypedNode::create(*FD));
2242 Result.addNode(Tag, DynTypedNode::create(*CE));
2243 Result.addNode(UnsafeSizedByTag, DynTypedNode::create(*CE));
2248 Result.addNode(Tag, DynTypedNode::create(*CE));
2255 const Stmt *getBaseStmt()
const {
return Call; }
2257 SourceLocation getSourceLoc()
const override {
return Call->getBeginLoc(); }
2259 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2260 bool IsRelatedToDecl,
2261 ASTContext &Ctx)
const override {
2265 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2267 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2270class UnsafeFormatAttributedFunctionCallGadget :
public WarningGadget {
2271 const CallExpr *
const Call;
2272 const Expr *UnsafeArg =
nullptr;
2273 constexpr static const char *
const Tag =
"UnsafeFormatAttributedFunctionCall";
2274 constexpr static const char *
const UnsafeStringTag =
2275 "UnsafeFormatAttributedFunctionCall_string";
2279 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2280 Call(
Result.getNodeAs<CallExpr>(Tag)),
2281 UnsafeArg(
Result.getNodeAs<Expr>(UnsafeStringTag)) {}
2283 static bool matches(
const Stmt *S, ASTContext &Ctx,
2284 const UnsafeBufferUsageHandler *Handler,
2288 auto *CE = dyn_cast<CallExpr>(S);
2289 if (!CE || !CE->getDirectCallee())
2291 const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
2295 const FormatAttr *Attr =
nullptr;
2296 bool IsPrintf =
false;
2297 bool AnyAttr = llvm::any_of(
2298 FD->specific_attrs<FormatAttr>(),
2299 [&Attr, &IsPrintf](
const FormatAttr *FA) ->
bool {
2300 if (const auto *II = FA->getType()) {
2301 if (II->getName() ==
"printf" || II->getName() ==
"scanf") {
2303 IsPrintf = II->getName() ==
"printf";
2309 const Expr *UnsafeArg;
2315 unsigned FmtIdx = Attr->getFormatIdx() - 1;
2316 std::optional<unsigned> FmtArgIdx = Attr->getFirstArg() - 1;
2326 }
else if (CE->getStmtClass() != Stmt::CallExprClass &&
2329 if (*FmtArgIdx >= CE->getNumArgs())
2336 FmtArgIdx = std::nullopt;
2338 if (AnyAttr && !IsPrintf && FmtArgIdx) {
2340 Result.addNode(Tag, DynTypedNode::create(*CE));
2345 Ctx, CE, UnsafeArg, FmtIdx, FmtArgIdx)) {
2346 Result.addNode(Tag, DynTypedNode::create(*CE));
2347 Result.addNode(UnsafeStringTag, DynTypedNode::create(*UnsafeArg));
2353 const Stmt *getBaseStmt()
const {
return Call; }
2358 bool IsRelatedToDecl,
2363 UnsafeLibcFunctionCallGadget::UnsafeKind::STRING |
2364 UnsafeLibcFunctionCallGadget::UnsafeKind::FORMAT_ATTR,
2369 UnsafeLibcFunctionCallGadget::UnsafeKind::OTHERS |
2370 UnsafeLibcFunctionCallGadget::UnsafeKind::FORMAT_ATTR,
2374 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2382class ULCArraySubscriptGadget :
public FixableGadget {
2384 static constexpr const char *
const ULCArraySubscriptTag =
2385 "ArraySubscriptUnderULC";
2386 const ArraySubscriptExpr *Node;
2390 : FixableGadget(
Kind::ULCArraySubscript),
2391 Node(
Result.getNodeAs<ArraySubscriptExpr>(ULCArraySubscriptTag)) {
2392 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2395 static bool classof(
const Gadget *G) {
2396 return G->getKind() == Kind::ULCArraySubscript;
2399 static bool matches(
const Stmt *S,
2400 llvm::SmallVectorImpl<MatchResult> &Results) {
2401 size_t SizeBefore = Results.size();
2403 const auto *ASE = dyn_cast<ArraySubscriptExpr>(E);
2409 !isSupportedVariable(*DRE))
2412 R.addNode(ULCArraySubscriptTag, DynTypedNode::create(*ASE));
2413 Results.emplace_back(std::move(R));
2415 return SizeBefore != Results.size();
2418 virtual std::optional<FixItList>
2419 getFixits(
const FixitStrategy &S)
const override;
2420 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2422 virtual DeclUseList getClaimedVarUseSites()
const override {
2423 if (
const auto *DRE =
2424 dyn_cast<DeclRefExpr>(Node->getBase()->IgnoreImpCasts())) {
2434class UPCStandalonePointerGadget :
public FixableGadget {
2436 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
2437 const DeclRefExpr *Node;
2441 : FixableGadget(
Kind::UPCStandalonePointer),
2442 Node(
Result.getNodeAs<DeclRefExpr>(DeclRefExprTag)) {
2443 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2446 static bool classof(
const Gadget *G) {
2447 return G->getKind() == Kind::UPCStandalonePointer;
2450 static bool matches(
const Stmt *S,
2451 llvm::SmallVectorImpl<MatchResult> &Results) {
2452 size_t SizeBefore = Results.size();
2454 auto *E = dyn_cast<Expr>(S);
2459 !isSupportedVariable(*DRE))
2462 R.addNode(DeclRefExprTag, DynTypedNode::create(*DRE));
2463 Results.emplace_back(std::move(R));
2465 return SizeBefore != Results.size();
2468 virtual std::optional<FixItList>
2469 getFixits(
const FixitStrategy &S)
const override;
2470 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2472 virtual DeclUseList getClaimedVarUseSites()
const override {
return {Node}; }
2475class PointerDereferenceGadget :
public FixableGadget {
2476 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2477 static constexpr const char *
const OperatorTag =
"op";
2479 const DeclRefExpr *BaseDeclRefExpr =
nullptr;
2480 const UnaryOperator *Op =
nullptr;
2484 : FixableGadget(
Kind::PointerDereference),
2485 BaseDeclRefExpr(
Result.getNodeAs<DeclRefExpr>(BaseDeclRefExprTag)),
2486 Op(
Result.getNodeAs<UnaryOperator>(OperatorTag)) {}
2488 static bool classof(
const Gadget *G) {
2489 return G->getKind() == Kind::PointerDereference;
2492 static bool matches(
const Stmt *S,
2493 llvm::SmallVectorImpl<MatchResult> &Results) {
2494 size_t SizeBefore = Results.size();
2496 const auto *UO = dyn_cast<UnaryOperator>(S);
2499 const auto *CE = dyn_cast<Expr>(UO->
getSubExpr());
2502 CE = CE->IgnoreParenImpCasts();
2503 const auto *DRE = dyn_cast<DeclRefExpr>(CE);
2504 if (!DRE || !isSupportedVariable(*DRE))
2507 R.addNode(BaseDeclRefExprTag, DynTypedNode::create(*DRE));
2508 R.addNode(OperatorTag, DynTypedNode::create(*UO));
2509 Results.emplace_back(std::move(R));
2511 return SizeBefore != Results.size();
2514 DeclUseList getClaimedVarUseSites()
const override {
2515 return {BaseDeclRefExpr};
2518 virtual std::optional<FixItList>
2519 getFixits(
const FixitStrategy &S)
const override;
2520 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2526class UPCAddressofArraySubscriptGadget :
public FixableGadget {
2528 static constexpr const char *
const UPCAddressofArraySubscriptTag =
2529 "AddressofArraySubscriptUnderUPC";
2530 const UnaryOperator *Node;
2534 : FixableGadget(
Kind::ULCArraySubscript),
2535 Node(
Result.getNodeAs<UnaryOperator>(UPCAddressofArraySubscriptTag)) {
2536 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2539 static bool classof(
const Gadget *G) {
2540 return G->getKind() == Kind::UPCAddressofArraySubscript;
2543 static bool matches(
const Stmt *S,
2544 llvm::SmallVectorImpl<MatchResult> &Results) {
2545 size_t SizeBefore = Results.size();
2547 auto *E = dyn_cast<Expr>(S);
2551 if (!UO || UO->
getOpcode() != UO_AddrOf)
2553 const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->
getSubExpr());
2558 if (!DRE || !isSupportedVariable(*DRE))
2561 R.addNode(UPCAddressofArraySubscriptTag, DynTypedNode::create(*UO));
2562 Results.emplace_back(std::move(R));
2564 return SizeBefore != Results.size();
2567 virtual std::optional<FixItList>
2568 getFixits(
const FixitStrategy &)
const override;
2569 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2571 virtual DeclUseList getClaimedVarUseSites()
const override {
2584class DeclUseTracker {
2585 using UseSetTy = llvm::SmallPtrSet<const DeclRefExpr *, 16>;
2586 using DefMapTy = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
2589 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
2593 DeclUseTracker() =
default;
2594 DeclUseTracker(
const DeclUseTracker &) =
delete;
2595 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
2596 DeclUseTracker(DeclUseTracker &&) =
default;
2597 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
2600 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
2603 void claimUse(
const DeclRefExpr *DRE) {
2604 assert(Uses->count(DRE) &&
2605 "DRE not found or claimed by multiple matchers!");
2610 bool hasUnclaimedUses(
const VarDecl *VD)
const {
2612 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
2617 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
2619 for (
auto use : *Uses) {
2621 ReturnSet.insert(use);
2627 void discoverDecl(
const DeclStmt *DS) {
2628 for (
const Decl *D : DS->
decls()) {
2629 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
2640 const DeclStmt *lookupDecl(
const VarDecl *VD)
const {
2641 return Defs.lookup(VD);
2650 static constexpr const char *
const UPCPreIncrementTag =
2651 "PointerPreIncrementUnderUPC";
2656 : FixableGadget(Kind::UPCPreIncrement),
2658 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2662 return G->getKind() == Kind::UPCPreIncrement;
2671 size_t SizeBefore = Results.size();
2673 auto *E = dyn_cast<Expr>(S);
2677 if (!UO || UO->
getOpcode() != UO_PreInc)
2679 const auto *DRE = dyn_cast<DeclRefExpr>(UO->
getSubExpr());
2680 if (!DRE || !isSupportedVariable(*DRE))
2684 Results.emplace_back(std::move(R));
2686 return SizeBefore != Results.size();
2689 virtual std::optional<FixItList>
2694 return {dyn_cast<DeclRefExpr>(Node->getSubExpr())};
2702 static constexpr const char *
const UUCAddAssignTag =
2703 "PointerAddAssignUnderUUC";
2704 static constexpr const char *
const OffsetTag =
"Offset";
2707 const Expr *Offset =
nullptr;
2711 : FixableGadget(Kind::UUCAddAssign),
2714 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2718 return G->getKind() == Kind::UUCAddAssign;
2723 size_t SizeBefore = Results.size();
2725 const auto *E = dyn_cast<Expr>(S);
2729 if (!BO || BO->
getOpcode() != BO_AddAssign)
2731 const auto *DRE = dyn_cast<DeclRefExpr>(BO->
getLHS());
2737 Results.emplace_back(std::move(R));
2739 return SizeBefore != Results.size();
2742 virtual std::optional<FixItList>
2747 return {dyn_cast<DeclRefExpr>(Node->getLHS())};
2754 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2755 static constexpr const char *
const DerefOpTag =
"DerefOp";
2756 static constexpr const char *
const AddOpTag =
"AddOp";
2757 static constexpr const char *
const OffsetTag =
"Offset";
2766 : FixableGadget(Kind::DerefSimplePtrArithFixable),
2774 auto IsPtr = [](
const Expr *E, MatchResult &R) {
2778 if (!DRE || !isSupportedVariable(*DRE))
2783 const auto IsPlusOverPtrAndInteger = [&IsPtr](
const Expr *E,
2785 const auto *BO = dyn_cast<BinaryOperator>(E);
2789 const auto *LHS = BO->
getLHS();
2790 const auto *RHS = BO->
getRHS();
2803 size_t SizeBefore = Results.size();
2804 const auto InnerMatcher = [&IsPlusOverPtrAndInteger,
2805 &Results](
const Expr *E) {
2806 const auto *UO = dyn_cast<UnaryOperator>(E);
2812 if (IsPlusOverPtrAndInteger(Operand, R)) {
2814 Results.emplace_back(std::move(R));
2818 return SizeBefore != Results.size();
2821 virtual std::optional<FixItList>
2824 return DerefOp->getBeginLoc();
2828 return {BaseDeclRefExpr};
2836 : WarningGadgets(WarningGadgets) {}
2845#define WARNING_GADGET(name) \
2846 if (name##Gadget::matches(S, Ctx, Result) && \
2847 notInSafeBufferOptOut(*S, &Handler)) { \
2848 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2851#define WARNING_OPTIONAL_GADGET(name) \
2852 if (name##Gadget::matches(S, Ctx, &Handler, Result) && \
2853 notInSafeBufferOptOut(*S, &Handler)) { \
2854 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2857#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2862 WarningGadgetList &WarningGadgets;
2869 DeclUseTracker &Tracker)
2870 : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
2874 bool matchFound =
false;
2881#define FIXABLE_GADGET(name) \
2882 if (name##Gadget::matches(S, Results)) { \
2883 for (const auto &R : Results) { \
2884 FixableGadgets.push_back(std::make_unique<name##Gadget>(R)); \
2885 matchFound = true; \
2889#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2892 if (
auto *DRE = findDeclRefExpr(S); DRE) {
2893 Tracker.discoverUse(DRE);
2899 if (
auto *DS = findDeclStmt(S); DS) {
2900 Tracker.discoverDecl(DS);
2908 const auto *DRE = dyn_cast<DeclRefExpr>(S);
2916 const DeclStmt *findDeclStmt(
const Stmt *S) {
2917 const auto *DS = dyn_cast<DeclStmt>(S);
2922 FixableGadgetList &FixableGadgets;
2923 DeclUseTracker &Tracker;
2929 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2930 WarningGadgetList &WarningGadgets,
2931 DeclUseTracker &Tracker) {
2934 if (EmitSuggestions) {
2943 return N1->getBeginLoc().getRawEncoding() <
2944 N2->getBeginLoc().getRawEncoding();
2954 const Expr *UnsafeArg =
nullptr)
override {}
2962 bool IsRelatedToDecl,
2983 FixableGadgetList FixableGadgets;
2984 WarningGadgetList WarningGadgets;
2985 DeclUseTracker Tracker;
2986 MockReporter IgnoreHandler;
2989 FixableGadgets, WarningGadgets, Tracker);
2991 std::set<const Expr *>
Result;
2992 for (
auto &G : WarningGadgets) {
2993 for (
const Expr *E : G->getUnsafePtrs()) {
3002 std::map<const VarDecl *, std::set<const WarningGadget *>,
3016 for (
auto &G : AllUnsafeOperations) {
3017 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
3019 bool AssociatedWithVarDecl =
false;
3020 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
3021 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3022 result.
byVar[VD].insert(G.get());
3023 AssociatedWithVarDecl =
true;
3027 if (!AssociatedWithVarDecl) {
3028 result.
noVar.push_back(G.get());
3036 std::map<const VarDecl *, std::set<const FixableGadget *>,
3046 for (
auto &F : AllFixableOperations) {
3047 DeclUseList DREs = F->getClaimedVarUseSites();
3050 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3051 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
3055 return FixablesForUnsafeVars;
3062 std::vector<const FixItHint *>
All;
3066 std::sort(
All.begin(),
All.end(),
3068 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
3069 H2->RemoveRange.getBegin());
3077 Hint->RemoveRange.getBegin())) {
3089std::optional<FixItList>
3090PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
3093 switch (S.
lookup(LeftVD)) {
3097 return std::nullopt;
3099 return std::nullopt;
3102 return std::nullopt;
3104 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3106 return std::nullopt;
3110static inline std::optional<FixItList>
createDataFixit(
const ASTContext &Ctx,
3111 const DeclRefExpr *DRE);
3113std::optional<FixItList>
3114CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
3133 if (S.
lookup(LeftVD) == FixitStrategy::Kind::Span) {
3134 if (S.
lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
3137 }
else if (S.
lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
3138 if (S.
lookup(RightVD) == FixitStrategy::Kind::Array) {
3142 return std::nullopt;
3145std::optional<FixItList>
3146PointerInitGadget::getFixits(
const FixitStrategy &S)
const {
3147 const auto *LeftVD = PtrInitLHS;
3149 switch (S.
lookup(LeftVD)) {
3150 case FixitStrategy::Kind::Span:
3151 if (S.
lookup(RightVD) == FixitStrategy::Kind::Span)
3153 return std::nullopt;
3154 case FixitStrategy::Kind::Wontfix:
3155 return std::nullopt;
3156 case FixitStrategy::Kind::Iterator:
3157 case FixitStrategy::Kind::Array:
3158 return std::nullopt;
3159 case FixitStrategy::Kind::Vector:
3160 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3162 return std::nullopt;
3168 if (ConstVal->isNegative())
3175std::optional<FixItList>
3176ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
3177 if (
const auto *DRE =
3179 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3181 case FixitStrategy::Kind::Span: {
3185 const ASTContext &Ctx =
3188 return std::nullopt;
3192 case FixitStrategy::Kind::Array:
3194 case FixitStrategy::Kind::Wontfix:
3195 case FixitStrategy::Kind::Iterator:
3196 case FixitStrategy::Kind::Vector:
3197 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3200 return std::nullopt;
3203static std::optional<FixItList>
3206std::optional<FixItList>
3207UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
3208 auto DREs = getClaimedVarUseSites();
3212 case FixitStrategy::Kind::Span:
3214 case FixitStrategy::Kind::Wontfix:
3215 case FixitStrategy::Kind::Iterator:
3216 case FixitStrategy::Kind::Array:
3217 return std::nullopt;
3218 case FixitStrategy::Kind::Vector:
3219 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3221 return std::nullopt;
3226 static const char *
const EOL =
"\n";
3233 std::string
s = std::string(
"<# ");
3234 s += HintTextToUser;
3240template <
typename NodeTy>
3241static std::optional<SourceLocation>
3244 if (
unsigned TkLen =
3251 return std::nullopt;
3264 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
3265 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
3266 VD->getBeginLoc())) &&
3267 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
3268 At->getRange().getBegin()));
3272 AttrRangeOverlapping;
3314 std::optional<Qualifiers> Quals = std::nullopt) {
3315 const char *
const SpanOpen =
"std::span<";
3318 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
3319 return SpanOpen + EltTyText.str() +
'>';
3322std::optional<FixItList>
3324 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->getDecl());
3329 if (
auto ConstVal = Offset->getIntegerConstantExpr(Ctx))
3330 if (ConstVal->isNegative())
3331 return std::nullopt;
3352 const Expr *LHS = AddOp->getLHS(), *RHS = AddOp->getRHS();
3359 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
3361 return std::nullopt;
3366 std::optional<SourceLocation> AddOpLocation =
3368 std::optional<SourceLocation> DerefOpLocation =
3371 if (!AddOpLocation || !DerefOpLocation)
3372 return std::nullopt;
3382 return std::nullopt;
3385std::optional<FixItList>
3386PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
3397 if (
auto LocPastOperand =
3404 case FixitStrategy::Kind::Iterator:
3405 case FixitStrategy::Kind::Array:
3406 return std::nullopt;
3407 case FixitStrategy::Kind::Vector:
3408 llvm_unreachable(
"FixitStrategy not implemented yet!");
3409 case FixitStrategy::Kind::Wontfix:
3410 llvm_unreachable(
"Invalid strategy!");
3413 return std::nullopt;
3420 std::optional<SourceLocation> EndOfOperand =
3426 return std::nullopt;
3431std::optional<FixItList>
3432UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
3435 case FixitStrategy::Kind::Array:
3436 case FixitStrategy::Kind::Span: {
3441 case FixitStrategy::Kind::Wontfix:
3442 case FixitStrategy::Kind::Iterator:
3443 return std::nullopt;
3444 case FixitStrategy::Kind::Vector:
3445 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3448 return std::nullopt;
3453static std::optional<FixItList>
3460 const Expr *Idx = ArraySub->getIdx();
3463 std::stringstream SS;
3464 bool IdxIsLitZero =
false;
3467 if ((*ICE).isZero())
3468 IdxIsLitZero =
true;
3469 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
3471 return std::nullopt;
3475 SS << (*DreString).str() <<
".data()";
3477 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
3479 return std::nullopt;
3481 SS <<
"&" << (*DreString).str() <<
".data()"
3482 <<
"[" << (*IndexString).str() <<
"]";
3488std::optional<FixItList>
3492 if (DREs.size() != 1)
3493 return std::nullopt;
3495 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3499 const Stmt *AddAssignNode = Node;
3500 StringRef varName = VD->
getName();
3504 return std::nullopt;
3508 (Offset->IgnoreParens()->getBeginLoc() == Offset->getBeginLoc());
3509 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
3513 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
3515 if (!AddAssignLocation)
3516 return std::nullopt;
3523 Offset->getEndLoc().getLocWithOffset(1),
")"));
3527 return std::nullopt;
3530std::optional<FixItList>
3534 if (DREs.size() != 1)
3535 return std::nullopt;
3537 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3540 std::stringstream SS;
3541 StringRef varName = VD->
getName();
3545 SS <<
"(" << varName.data() <<
" = " << varName.data()
3546 <<
".subspan(1)).data()";
3547 std::optional<SourceLocation> PreIncLocation =
3549 if (!PreIncLocation)
3550 return std::nullopt;
3553 SourceRange(Node->getBeginLoc(), *PreIncLocation), SS.str()));
3557 return std::nullopt;
3575static std::optional<FixItList>
3577 const StringRef UserFillPlaceHolder) {
3585 if (
Init->isNullPointerConstant(
3590 NPC_ValueDependentIsNotNull)) {
3591 std::optional<SourceLocation> InitLocation =
3594 return std::nullopt;
3602 std::string ExtentText = UserFillPlaceHolder.data();
3603 StringRef One =
"1";
3608 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
3613 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
3614 if (!Ext->HasSideEffects(Ctx)) {
3615 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
3617 return std::nullopt;
3618 ExtentText = *ExtentString;
3620 }
else if (!CxxNew->isArray())
3632 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
3633 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
3634 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
3641 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
3644 return std::nullopt;
3646 StrBuffer.append(
", ");
3647 StrBuffer.append(ExtentText);
3648 StrBuffer.append(
"}");
3654#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
3655 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
3656 "failed to produce fixit for declaration '" + \
3657 (D)->getNameAsString() + "'" + (Msg))
3659#define DEBUG_NOTE_DECL_FAIL(D, Msg)
3665static std::optional<std::string>
3669 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3674 return std::nullopt;
3676 std::string SpanTyText =
"std::span<";
3678 SpanTyText.append(*PteTyText);
3680 if (PteTyQualifiers) {
3681 SpanTyText.append(
" ");
3682 SpanTyText.append(PteTyQualifiers->getAsString());
3684 SpanTyText.append(
">");
3703 const StringRef UserFillPlaceHolder,
3717 std::stringstream SS;
3722 std::optional<FixItList> InitFixIts =
3726 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
3727 std::make_move_iterator(InitFixIts->end()));
3734 if (!EndLocForReplacement.
isValid()) {
3784static std::optional<FixItList>
3790 return std::nullopt;
3795 std::vector<std::string> NewTysTexts(NumParms);
3796 std::vector<bool> ParmsMask(NumParms,
false);
3797 bool AtLeastOneParmToFix =
false;
3799 for (
unsigned i = 0; i < NumParms; i++) {
3806 return std::nullopt;
3808 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3809 std::optional<std::string> PteTyText =
3814 return std::nullopt;
3818 ParmsMask[i] =
true;
3819 AtLeastOneParmToFix =
true;
3821 if (!AtLeastOneParmToFix)
3828 const auto NewOverloadSignatureCreator =
3829 [&
SM, &LangOpts, &NewTysTexts,
3830 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3831 std::stringstream SS;
3839 SS << Prefix->str();
3841 return std::nullopt;
3845 for (
unsigned i = 0; i < NumParms; i++) {
3853 SS << NewTysTexts[i];
3856 SS <<
' ' << II->getName().str();
3857 }
else if (
auto ParmTypeText =
3861 SS << ParmTypeText->str();
3863 return std::nullopt;
3864 if (i != NumParms - 1)
3873 const auto OldOverloadDefCreator =
3874 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3875 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3876 std::stringstream SS;
3884 << FDPrefix->str() <<
"{";
3886 return std::nullopt;
3889 SS <<
"return " << FunQualName->str() <<
"(";
3891 return std::nullopt;
3895 for (
unsigned i = 0; i < NumParms; i++) {
3904 return std::nullopt;
3911 if (i != NumParms - 1)
3922 std::optional<SourceLocation> Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3926 if (FReDecl->isThisDeclarationADefinition()) {
3927 assert(FReDecl == FD &&
"inconsistent function definition");
3930 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3936 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3939 FReDecl->getBeginLoc(),
" ")));
3942 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3964 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3980 std::stringstream SS;
3983 if (PteTyQualifiers)
3992 SS <<
' ' << PVDNameText->str();
3998 const DeclUseTracker &Tracker,
4001 const DeclStmt *DS = Tracker.lookupDecl(VD);
4004 " : variables declared this way not implemented yet");
4028 const QualType &ArrayEltT = CAT->getElementType();
4029 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
4038 auto MaybeElemTypeTxt =
4041 if (!MaybeElemTypeTxt)
4043 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
4048 while (NextTok && !NextTok->is(tok::l_square) &&
4061 if (!MaybeArraySizeTxt)
4063 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
4064 if (ArraySizeTxt.empty()) {
4075 std::optional<StringRef> IdentText =
4084 llvm::raw_svector_ostream OS(Replacement);
4085 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
4086 << IdentText->str();
4096 const DeclUseTracker &Tracker,
4099 const DeclStmt *DS = Tracker.lookupDecl(VD);
4100 assert(DS &&
"Fixing non-local variables not implemented yet!");
4119 const DeclUseTracker &Tracker,
ASTContext &Ctx,
4121 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
4122 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
4123 if (!FD || FD != D) {
4134 if (FD->isMain() || FD->isConstexpr() ||
4141 FD->isOverloadedOperator()) {
4150 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
4168 llvm_unreachable(
"FixitStrategy not implemented yet!");
4170 llvm_unreachable(
"Invalid strategy!");
4172 llvm_unreachable(
"Unknown strategy!");
4180 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
4182 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
4199 std::map<const VarDecl *, FixItList> &FixItsForVariable,
4204 for (
const auto &[VD, Ignore] : FixItsForVariable) {
4206 if (llvm::any_of(Grp,
4207 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
4208 return !FixItsForVariable.count(GrpMember);
4213 ToErase.push_back(
Member);
4216 for (
auto *VarToErase : ToErase)
4217 FixItsForVariable.erase(VarToErase);
4228 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
4232 FixItList FixItsSharedByParms{};
4234 std::optional<FixItList> OverloadFixes =
4237 if (OverloadFixes) {
4238 FixItsSharedByParms.append(*OverloadFixes);
4244 FixItsForVariable.erase(
Member);
4246 return FixItsSharedByParms;
4250static std::map<const VarDecl *, FixItList>
4259 std::map<const VarDecl *, FixItList> FixItsForVariable;
4264 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
4265 FixItsForVariable[VD] =
4269 if (FixItsForVariable[VD].empty()) {
4270 FixItsForVariable.erase(VD);
4273 for (
const auto &F : Fixables) {
4274 std::optional<FixItList> Fixits = F->getFixits(S);
4277 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
4278 Fixits->begin(), Fixits->end());
4283 VD, F->getSourceLoc(),
4284 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
4287 FixItsForVariable.erase(VD);
4306 FixItList FixItsSharedByParms{};
4308 if (
auto *FD = dyn_cast<FunctionDecl>(D))
4310 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
4314 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
4317 for (
auto &[Var, Ignore] : FixItsForVariable) {
4318 bool AnyParm =
false;
4319 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
4321 for (
const VarDecl *GrpMate : VarGroupForVD) {
4324 if (FixItsForVariable.count(GrpMate))
4325 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
4329 assert(!FixItsSharedByParms.empty() &&
4330 "Should not try to fix a parameter that does not belong to a "
4332 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
4339 for (
auto Iter = FinalFixItsForVariable.begin();
4340 Iter != FinalFixItsForVariable.end();)
4343 Iter = FinalFixItsForVariable.erase(Iter);
4346 return FinalFixItsForVariable;
4349template <
typename VarDeclIterTy>
4353 for (
const VarDecl *VD : UnsafeVars) {
4364 const std::vector<VarGrpTy> &Groups;
4365 const std::map<const VarDecl *, unsigned> &VarGrpMap;
4366 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
4370 const std::vector<VarGrpTy> &Groups,
4371 const std::map<const VarDecl *, unsigned> &VarGrpMap,
4372 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
4373 : Groups(Groups), VarGrpMap(VarGrpMap),
4374 GrpsUnionForParms(GrpsUnionForParms) {}
4377 if (GrpsUnionForParms.contains(Var)) {
4380 return GrpsUnionForParms.getArrayRef();
4385 auto It = VarGrpMap.find(Var);
4387 if (It == VarGrpMap.end())
4389 return Groups[It->second];
4393 return GrpsUnionForParms.getArrayRef();
4398 WarningGadgetList WarningGadgets,
4399 DeclUseTracker Tracker,
4401 bool EmitSuggestions) {
4402 if (!EmitSuggestions) {
4406 for (
const auto &G : WarningGadgets) {
4407 G->handleUnsafeOperation(Handler,
false,
4413 assert(FixableGadgets.empty() &&
4414 "Fixable gadgets found but suggestions not requested!");
4420 if (!WarningGadgets.empty()) {
4424 for (
const auto &G : FixableGadgets) {
4425 for (
const auto *DRE : G->getClaimedVarUseSites()) {
4426 Tracker.claimUse(DRE);
4442 if (WarningGadgets.empty())
4450 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
4453 for (
auto it = FixablesForAllVars.
byVar.cbegin();
4454 it != FixablesForAllVars.
byVar.cend();) {
4459 (
"failed to produce fixit for '" +
4460 it->first->getNameAsString() +
4461 "' : neither local nor a parameter"));
4463 it = FixablesForAllVars.
byVar.erase(it);
4464 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
4467 (
"failed to produce fixit for '" +
4468 it->first->getNameAsString() +
4469 "' : has a reference type"));
4471 it = FixablesForAllVars.
byVar.erase(it);
4472 }
else if (Tracker.hasUnclaimedUses(it->first)) {
4473 it = FixablesForAllVars.
byVar.erase(it);
4474 }
else if (it->first->isInitCapture()) {
4477 (
"failed to produce fixit for '" +
4478 it->first->getNameAsString() +
4479 "' : init capture"));
4481 it = FixablesForAllVars.
byVar.erase(it);
4488 for (
const auto &it : UnsafeOps.
byVar) {
4489 const VarDecl *
const UnsafeVD = it.first;
4490 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
4491 if (UnclaimedDREs.empty())
4495 std::string UnclaimedUseTrace =
4500 (
"failed to produce fixit for '" + UnfixedVDName +
4501 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
4502 UnclaimedUseTrace));
4509 llvm::DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
4510 DepMapTy DependenciesMap{};
4511 DepMapTy PtrAssignmentGraph{};
4513 for (
const auto &it : FixablesForAllVars.
byVar) {
4514 for (
const FixableGadget *fixable : it.second) {
4515 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
4516 fixable->getStrategyImplications();
4518 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
4519 PtrAssignmentGraph[Impl.first].insert(Impl.second);
4541 std::set<const VarDecl *> VisitedVarsDirected{};
4542 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4543 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
4545 std::queue<const VarDecl *> QueueDirected{};
4546 QueueDirected.push(Var);
4547 while (!QueueDirected.empty()) {
4548 const VarDecl *CurrentVar = QueueDirected.front();
4549 QueueDirected.pop();
4550 VisitedVarsDirected.insert(CurrentVar);
4551 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
4552 for (
const VarDecl *Adj : AdjacentNodes) {
4553 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
4554 QueueDirected.push(Adj);
4556 DependenciesMap[Var].insert(Adj);
4557 DependenciesMap[Adj].insert(Var);
4564 std::vector<VarGrpTy> Groups;
4568 std::map<const VarDecl *, unsigned> VarGrpMap;
4570 llvm::SetVector<const VarDecl *>
4575 std::set<const VarDecl *> VisitedVars{};
4576 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4577 if (VisitedVars.find(Var) == VisitedVars.end()) {
4578 VarGrpTy &VarGroup = Groups.emplace_back();
4579 std::queue<const VarDecl *> Queue{};
4582 while (!Queue.empty()) {
4583 const VarDecl *CurrentVar = Queue.front();
4585 VisitedVars.insert(CurrentVar);
4586 VarGroup.push_back(CurrentVar);
4587 auto AdjacentNodes = DependenciesMap[CurrentVar];
4588 for (
const VarDecl *Adj : AdjacentNodes) {
4589 if (VisitedVars.find(Adj) == VisitedVars.end()) {
4595 bool HasParm =
false;
4596 unsigned GrpIdx = Groups.size() - 1;
4598 for (
const VarDecl *
V : VarGroup) {
4599 VarGrpMap[
V] = GrpIdx;
4604 GrpsUnionForParms.insert_range(VarGroup);
4626 for (
auto I = FixablesForAllVars.
byVar.begin();
4627 I != FixablesForAllVars.
byVar.end();) {
4629 if (!VisitedVars.count((*I).first)) {
4631 I = FixablesForAllVars.
byVar.erase(I);
4639 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
4641 return FixablesForAllVars.
byVar.count(
V);
4648 FixItsForVariableGroup =
4650 Tracker, Handler, VarGrpMgr);
4652 for (
const auto &G : UnsafeOps.
noVar) {
4653 G->handleUnsafeOperation(Handler,
false,
4657 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
4658 auto FixItsIt = FixItsForVariableGroup.find(VD);
4660 FixItsIt != FixItsForVariableGroup.end()
4661 ? std::move(FixItsIt->second)
4664 for (
const auto &G : WarningGadgets) {
4665 G->handleUnsafeOperation(Handler,
true,
4673 bool EmitSuggestions) {
4682 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
4685 if (FD->isConsteval())
4690 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
4691 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
4696 if (FReDecl->isExternC()) {
4699 EmitSuggestions =
false;
4704 Stmts.push_back(FD->getBody());
4706 if (
const auto *ID = dyn_cast<CXXConstructorDecl>(D)) {
4708 Stmts.push_back(CI->getInit());
4712 Stmts.push_back(D->
getBody());
4715 assert(!Stmts.empty());
4717 FixableGadgetList FixableGadgets;
4718 WarningGadgetList WarningGadgets;
4719 DeclUseTracker Tracker;
4720 for (
Stmt *S : Stmts) {
4722 WarningGadgets, Tracker);
4724 applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
4725 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)
#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 const Expr * getSubExprInSizeOfExpr(const Expr &E)
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 bool isPtrBufferSafe(const Expr *Ptr, const Expr *Size, ASTContext &Ctx)
static const Expr * getSubExprInAddressOfExpr(const Expr &E)
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 byte-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.
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 StringRef matchLibcNameOrBuiltinChk(StringRef Name)
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 StringRef matchLibcName(StringRef Name)
static bool isUnsafeMemset(const CallExpr &Node, ASTContext &Ctx)
static StringRef matchName(StringRef FunName, bool isBuiltin)
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.