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 const std::set<StringRef> PredefinedNames = {
1114 if (PredefinedNames.count(Name))
1117 std::string NameWCS = Name.str();
1118 size_t WcsPos = NameWCS.find(
"wcs");
1120 while (WcsPos != std::string::npos) {
1121 NameWCS[WcsPos++] =
's';
1122 NameWCS[WcsPos++] =
't';
1123 NameWCS[WcsPos++] =
'r';
1124 WcsPos = NameWCS.find(
"wcs", WcsPos);
1126 if (PredefinedNames.count(NameWCS))
1130 return Name.ends_with(
"scanf");
1138 assert(FD &&
"It should have been checked that FD is non-null.");
1145 if (Name !=
"memset")
1157 const auto *AddressOfVar = dyn_cast_if_present<DeclRefExpr>(
1162 const auto *SizeOfVar =
1167 return AddressOfVar->getDecl() != SizeOfVar->getDecl();
1181 return Name.starts_with(
"v") && Name.ends_with(
"printf");
1194 return Name ==
"sprintf" || Name ==
"swprintf";
1208 if (!Name.ends_with(
"printf"))
1211 StringRef Prefix = Name.drop_back(6);
1213 if (Prefix.ends_with(
"w"))
1214 Prefix = Prefix.drop_back(1);
1216 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
1224 MatchResult &Result, llvm::StringRef Tag) {
1228 assert(FD &&
"It should have been checked that FD is non-null.");
1246 const Expr *UnsafeArg;
1257 bool isKprintf =
false;
1258 const Expr *UnsafeArg;
1261 isKprintf = II->getName() ==
"kprintf";
1263 std::nullopt, isKprintf)) {
1276 const Expr *UnsafeArg;
1287 for (
const auto *Arg : Node.
arguments())
1302 assert(FD &&
"It should have been checked that FD is non-null.");
1317 !Size->getType()->isUnsignedIntegerType())
1346#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1349 Gadget(Kind K) : K(K) {}
1351 Kind
getKind()
const {
return K; }
1354 StringRef getDebugName()
const {
1359#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1361 llvm_unreachable(
"Unhandled Gadget::Kind enum");
1365 virtual bool isWarningGadget()
const = 0;
1368 virtual SourceLocation getSourceLoc()
const = 0;
1373 virtual DeclUseList getClaimedVarUseSites()
const = 0;
1375 virtual ~Gadget() =
default;
1383class WarningGadget :
public Gadget {
1385 WarningGadget(Kind K) : Gadget(K) {}
1387 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1388 bool isWarningGadget() const final {
return true; }
1390 virtual void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1391 bool IsRelatedToDecl,
1392 ASTContext &Ctx)
const = 0;
1394 virtual SmallVector<const Expr *, 1> getUnsafePtrs()
const = 0;
1401class FixableGadget :
public Gadget {
1403 FixableGadget(Kind K) : Gadget(K) {}
1405 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1406 bool isWarningGadget() const final {
return false; }
1411 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1412 return std::nullopt;
1421 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1422 getStrategyImplications()
const {
1423 return std::nullopt;
1427static bool isSupportedVariable(
const DeclRefExpr &Node) {
1439 dyn_cast<ClassTemplateSpecializationDecl>(
RecordDecl);
1440 if (!class_template_specialization_decl)
1445 if (template_args.
size() == 0)
1456class UniquePtrArrayAccessGadget :
public WarningGadget {
1458 static constexpr const char *
const AccessorTag =
"unique_ptr_array_access";
1459 const CXXOperatorCallExpr *AccessorExpr;
1463 : WarningGadget(
Kind::UniquePtrArrayAccess),
1464 AccessorExpr(
Result.getNodeAs<CXXOperatorCallExpr>(AccessorTag)) {
1465 assert(AccessorExpr &&
1466 "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr");
1469 static bool classof(
const Gadget *G) {
1470 return G->getKind() == Kind::UniquePtrArrayAccess;
1473 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1476 const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(S);
1477 if (!OpCall || OpCall->
getOperator() != OO_Subscript)
1484 const CXXMethodDecl *
Method =
1489 if (
Method->getOverloadedOperator() != OO_Subscript)
1493 if (!isUniquePtrArray(RecordDecl))
1496 const Expr *IndexExpr = OpCall->
getArg(1);
1497 clang::Expr::EvalResult Eval;
1503 Result.addNode(AccessorTag, DynTypedNode::create(*OpCall));
1506 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1507 bool IsRelatedToDecl,
1508 ASTContext &Ctx)
const override {
1510 DynTypedNode::create(*AccessorExpr), IsRelatedToDecl, Ctx);
1513 SourceLocation getSourceLoc()
const override {
1515 return AccessorExpr->getOperatorLoc();
1516 return SourceLocation();
1519 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1520 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1523using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1524using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1528class IncrementGadget :
public WarningGadget {
1529 static constexpr const char *
const OpTag =
"op";
1530 const UnaryOperator *Op;
1534 : WarningGadget(
Kind::Increment),
1535 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1537 static bool classof(
const Gadget *G) {
1538 return G->getKind() == Kind::Increment;
1541 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1543 const auto *UO = dyn_cast<UnaryOperator>(S);
1548 Result.addNode(OpTag, DynTypedNode::create(*UO));
1552 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1553 bool IsRelatedToDecl,
1554 ASTContext &Ctx)
const override {
1557 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1559 DeclUseList getClaimedVarUseSites()
const override {
1560 SmallVector<const DeclRefExpr *, 2> Uses;
1561 if (
const auto *DRE =
1562 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1563 Uses.push_back(DRE);
1566 return std::move(Uses);
1569 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1570 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1576class DecrementGadget :
public WarningGadget {
1577 static constexpr const char *
const OpTag =
"op";
1578 const UnaryOperator *Op;
1582 : WarningGadget(
Kind::Decrement),
1583 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1585 static bool classof(
const Gadget *G) {
1586 return G->getKind() == Kind::Decrement;
1589 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1591 const auto *UO = dyn_cast<UnaryOperator>(S);
1596 Result.addNode(OpTag, DynTypedNode::create(*UO));
1600 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1601 bool IsRelatedToDecl,
1602 ASTContext &Ctx)
const override {
1605 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1607 DeclUseList getClaimedVarUseSites()
const override {
1608 if (
const auto *DRE =
1609 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1616 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1617 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1623class ArraySubscriptGadget :
public WarningGadget {
1624 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1625 const ArraySubscriptExpr *ASE;
1630 ASE(
Result.getNodeAs<ArraySubscriptExpr>(ArraySubscrTag)) {}
1632 static bool classof(
const Gadget *G) {
1633 return G->getKind() == Kind::ArraySubscript;
1636 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1637 const UnsafeBufferUsageHandler *Handler,
1639 const auto *ASE = dyn_cast<ArraySubscriptExpr>(S);
1642 const auto *
const Base = ASE->getBase()->IgnoreParenImpCasts();
1645 const auto *Idx = dyn_cast<IntegerLiteral>(ASE->getIdx());
1646 bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
1653 Result.addNode(ArraySubscrTag, DynTypedNode::create(*ASE));
1657 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1658 bool IsRelatedToDecl,
1659 ASTContext &Ctx)
const override {
1662 SourceLocation getSourceLoc()
const override {
return ASE->getBeginLoc(); }
1664 DeclUseList getClaimedVarUseSites()
const override {
1665 if (
const auto *DRE =
1666 dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
1673 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1674 return {ASE->getBase()->IgnoreParenImpCasts()};
1682class PointerArithmeticGadget :
public WarningGadget {
1683 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1684 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1685 const BinaryOperator *PA;
1690 : WarningGadget(
Kind::PointerArithmetic),
1691 PA(
Result.getNodeAs<BinaryOperator>(PointerArithmeticTag)),
1692 Ptr(
Result.getNodeAs<Expr>(PointerArithmeticPointerTag)) {}
1694 static bool classof(
const Gadget *G) {
1695 return G->getKind() == Kind::PointerArithmetic;
1698 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1700 const auto *BO = dyn_cast<BinaryOperator>(S);
1703 const auto *LHS = BO->
getLHS();
1704 const auto *RHS = BO->
getRHS();
1709 RHS->getType()->isEnumeralType())) {
1710 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*LHS));
1711 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1717 (LHS->getType()->isIntegerType() || LHS->getType()->isEnumeralType())) {
1718 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*RHS));
1719 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1725 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1726 bool IsRelatedToDecl,
1727 ASTContext &Ctx)
const override {
1730 SourceLocation getSourceLoc()
const override {
return PA->getBeginLoc(); }
1732 DeclUseList getClaimedVarUseSites()
const override {
1733 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts())) {
1740 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1741 return {Ptr->IgnoreParenImpCasts()};
1748class SpanTwoParamConstructorGadget :
public WarningGadget {
1749 static constexpr const char *
const SpanTwoParamConstructorTag =
1750 "spanTwoParamConstructor";
1751 const CXXConstructExpr *Ctor;
1755 : WarningGadget(
Kind::SpanTwoParamConstructor),
1756 Ctor(
Result.getNodeAs<CXXConstructExpr>(SpanTwoParamConstructorTag)) {}
1758 static bool classof(
const Gadget *G) {
1759 return G->getKind() == Kind::SpanTwoParamConstructor;
1763 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1766 const auto *CDecl = CE->getConstructor();
1767 const auto *CRecordDecl = CDecl->getParent();
1768 auto HasTwoParamSpanCtorDecl =
1769 CRecordDecl->isInStdNamespace() &&
1770 CDecl->getDeclName().getAsString() ==
"span" && CE->getNumArgs() == 2;
1773 Result.addNode(SpanTwoParamConstructorTag, DynTypedNode::create(*CE));
1777 static bool matches(
const Stmt *S, ASTContext &Ctx,
1778 const UnsafeBufferUsageHandler *Handler,
1785 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1786 bool IsRelatedToDecl,
1787 ASTContext &Ctx)
const override {
1790 SourceLocation getSourceLoc()
const override {
return Ctor->getBeginLoc(); }
1792 DeclUseList getClaimedVarUseSites()
const override {
1795 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->getArg(0))) {
1802 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1809class PointerInitGadget :
public FixableGadget {
1811 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1812 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1813 const VarDecl *PtrInitLHS;
1814 const DeclRefExpr *PtrInitRHS;
1818 : FixableGadget(
Kind::PointerInit),
1819 PtrInitLHS(
Result.getNodeAs<VarDecl>(PointerInitLHSTag)),
1820 PtrInitRHS(
Result.getNodeAs<DeclRefExpr>(PointerInitRHSTag)) {}
1822 static bool classof(
const Gadget *G) {
1823 return G->getKind() == Kind::PointerInit;
1826 static bool matches(
const Stmt *S,
1827 llvm::SmallVectorImpl<MatchResult> &Results) {
1828 const DeclStmt *DS = dyn_cast<DeclStmt>(S);
1837 const auto *DRE = dyn_cast<DeclRefExpr>(
Init->IgnoreImpCasts());
1838 if (!DRE || !
hasPointerType(*DRE) || !isSupportedVariable(*DRE)) {
1842 R.addNode(PointerInitLHSTag, DynTypedNode::create(*VD));
1843 R.addNode(PointerInitRHSTag, DynTypedNode::create(*DRE));
1844 Results.emplace_back(std::move(R));
1848 virtual std::optional<FixItList>
1849 getFixits(
const FixitStrategy &S)
const override;
1850 SourceLocation getSourceLoc()
const override {
1851 return PtrInitRHS->getBeginLoc();
1854 virtual DeclUseList getClaimedVarUseSites()
const override {
1855 return DeclUseList{PtrInitRHS};
1858 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1859 getStrategyImplications()
const override {
1860 return std::make_pair(PtrInitLHS,
cast<VarDecl>(PtrInitRHS->getDecl()));
1869class PtrToPtrAssignmentGadget :
public FixableGadget {
1871 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1872 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1873 const DeclRefExpr *PtrLHS;
1874 const DeclRefExpr *PtrRHS;
1878 : FixableGadget(
Kind::PtrToPtrAssignment),
1879 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1880 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1882 static bool classof(
const Gadget *G) {
1883 return G->getKind() == Kind::PtrToPtrAssignment;
1886 static bool matches(
const Stmt *S,
1887 llvm::SmallVectorImpl<MatchResult> &Results) {
1888 size_t SizeBefore = Results.size();
1890 const auto *BO = dyn_cast<BinaryOperator>(S);
1891 if (!BO || BO->
getOpcode() != BO_Assign)
1894 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1896 !isSupportedVariable(*RHSRef)) {
1899 const auto *LHS = BO->
getLHS();
1900 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1902 !isSupportedVariable(*LHSRef)) {
1906 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1907 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1908 Results.emplace_back(std::move(R));
1910 return SizeBefore != Results.size();
1913 virtual std::optional<FixItList>
1914 getFixits(
const FixitStrategy &S)
const override;
1915 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1917 virtual DeclUseList getClaimedVarUseSites()
const override {
1918 return DeclUseList{PtrLHS, PtrRHS};
1921 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1922 getStrategyImplications()
const override {
1933class CArrayToPtrAssignmentGadget :
public FixableGadget {
1935 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1936 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1937 const DeclRefExpr *PtrLHS;
1938 const DeclRefExpr *PtrRHS;
1942 : FixableGadget(
Kind::CArrayToPtrAssignment),
1943 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1944 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1946 static bool classof(
const Gadget *G) {
1947 return G->getKind() == Kind::CArrayToPtrAssignment;
1950 static bool matches(
const Stmt *S,
1951 llvm::SmallVectorImpl<MatchResult> &Results) {
1952 size_t SizeBefore = Results.size();
1954 const auto *BO = dyn_cast<BinaryOperator>(S);
1955 if (!BO || BO->
getOpcode() != BO_Assign)
1958 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1961 !isSupportedVariable(*RHSRef)) {
1964 const auto *LHS = BO->
getLHS();
1965 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1967 !isSupportedVariable(*LHSRef)) {
1971 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1972 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1973 Results.emplace_back(std::move(R));
1975 return SizeBefore != Results.size();
1978 virtual std::optional<FixItList>
1979 getFixits(
const FixitStrategy &S)
const override;
1980 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1982 virtual DeclUseList getClaimedVarUseSites()
const override {
1983 return DeclUseList{PtrLHS, PtrRHS};
1986 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1987 getStrategyImplications()
const override {
1994class UnsafeBufferUsageAttrGadget :
public WarningGadget {
1995 constexpr static const char *
const OpTag =
"attr_expr";
2000 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
2001 Op(
Result.getNodeAs<Expr>(OpTag)) {}
2003 static bool classof(
const Gadget *G) {
2004 return G->getKind() == Kind::UnsafeBufferUsageAttr;
2007 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2009 if (
auto *CE = dyn_cast<CallExpr>(S)) {
2010 if (CE->getDirectCallee() &&
2011 CE->getDirectCallee()->hasAttr<UnsafeBufferUsageAttr>()) {
2012 Result.addNode(OpTag, DynTypedNode::create(*CE));
2016 if (
auto *ME = dyn_cast<MemberExpr>(S)) {
2019 if (ME->getMemberDecl()->hasAttr<UnsafeBufferUsageAttr>()) {
2020 Result.addNode(OpTag, DynTypedNode::create(*ME));
2027 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2028 bool IsRelatedToDecl,
2029 ASTContext &Ctx)
const override {
2032 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2034 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2036 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2042class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
2043 constexpr static const char *
const OpTag =
"cxx_construct_expr";
2044 const CXXConstructExpr *Op;
2048 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
2049 Op(
Result.getNodeAs<CXXConstructExpr>(OpTag)) {}
2051 static bool classof(
const Gadget *G) {
2052 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
2056 const auto *CE = dyn_cast<CXXConstructExpr>(S);
2057 if (!CE || !CE->getConstructor()->hasAttr<UnsafeBufferUsageAttr>())
2061 if (SpanTwoParamConstructorGadget::matches(CE, Ctx, Tmp))
2063 Result.addNode(OpTag, DynTypedNode::create(*CE));
2067 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2068 bool IsRelatedToDecl,
2069 ASTContext &Ctx)
const override {
2072 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2074 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2076 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2083class DataInvocationGadget :
public WarningGadget {
2084 constexpr static const char *
const OpTag =
"data_invocation_expr";
2085 const ExplicitCastExpr *Op;
2089 : WarningGadget(
Kind::DataInvocation),
2090 Op(
Result.getNodeAs<ExplicitCastExpr>(OpTag)) {}
2092 static bool classof(
const Gadget *G) {
2093 return G->getKind() == Kind::DataInvocation;
2096 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2098 auto *CE = dyn_cast<ExplicitCastExpr>(S);
2101 for (
auto *Child : CE->children()) {
2102 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Child);
2103 MCE && isDataFunction(MCE)) {
2104 Result.addNode(OpTag, DynTypedNode::create(*CE));
2107 if (
auto *
Paren = dyn_cast<ParenExpr>(Child)) {
2108 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(
Paren->getSubExpr());
2109 MCE && isDataFunction(MCE)) {
2110 Result.addNode(OpTag, DynTypedNode::create(*CE));
2118 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2119 bool IsRelatedToDecl,
2120 ASTContext &Ctx)
const override {
2123 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2125 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2128 static bool isDataFunction(
const CXXMemberCallExpr *call) {
2135 if (method->getNameAsString() ==
"data" &&
2136 method->getParent()->isInStdNamespace() &&
2137 llvm::is_contained({SIZED_CONTAINER_OR_VIEW_LIST},
2138 method->getParent()->getName()))
2143 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2146class UnsafeLibcFunctionCallGadget :
public WarningGadget {
2147 const CallExpr *
const Call;
2148 const Expr *UnsafeArg =
nullptr;
2149 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
2151 constexpr static const char *
const UnsafeSprintfTag =
2152 "UnsafeLibcFunctionCall_sprintf";
2153 constexpr static const char *
const UnsafeSizedByTag =
2154 "UnsafeLibcFunctionCall_sized_by";
2155 constexpr static const char *
const UnsafeStringTag =
2156 "UnsafeLibcFunctionCall_string";
2157 constexpr static const char *
const UnsafeVaListTag =
2158 "UnsafeLibcFunctionCall_va_list";
2172 } WarnedFunKind = OTHERS;
2175 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2176 Call(
Result.getNodeAs<CallExpr>(Tag)) {
2177 if (
Result.getNodeAs<Decl>(UnsafeSprintfTag))
2178 WarnedFunKind = SPRINTF;
2179 else if (
auto *E =
Result.getNodeAs<Expr>(UnsafeStringTag)) {
2180 WarnedFunKind = STRING;
2182 }
else if (
Result.getNodeAs<CallExpr>(UnsafeSizedByTag)) {
2183 WarnedFunKind = SIZED_BY;
2184 UnsafeArg = Call->getArg(0);
2185 }
else if (
Result.getNodeAs<Decl>(UnsafeVaListTag))
2186 WarnedFunKind = VA_LIST;
2189 static bool matches(
const Stmt *S, ASTContext &Ctx,
2190 const UnsafeBufferUsageHandler *Handler,
2194 const auto *CE = dyn_cast<CallExpr>(S);
2197 const auto *FD = CE->getDirectCallee();
2201 const bool IsGlobalAndNotInAnyNamespace =
2202 FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
2206 if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
2213 const bool isSingleStringLiteralArg =
2214 CE->getNumArgs() == 1 &&
2216 if (!isSingleStringLiteralArg) {
2219 Result.addNode(Tag, DynTypedNode::create(*CE));
2223 Result.addNode(Tag, DynTypedNode::create(*CE));
2227 Result.addNode(Tag, DynTypedNode::create(*CE));
2228 Result.addNode(UnsafeVaListTag, DynTypedNode::create(*FD));
2232 Result.addNode(Tag, DynTypedNode::create(*CE));
2233 Result.addNode(UnsafeSprintfTag, DynTypedNode::create(*FD));
2239 Result.addNode(Tag, DynTypedNode::create(*CE));
2240 Result.addNode(UnsafeSizedByTag, DynTypedNode::create(*CE));
2245 Result.addNode(Tag, DynTypedNode::create(*CE));
2252 const Stmt *getBaseStmt()
const {
return Call; }
2254 SourceLocation getSourceLoc()
const override {
return Call->getBeginLoc(); }
2256 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2257 bool IsRelatedToDecl,
2258 ASTContext &Ctx)
const override {
2262 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2264 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2267class UnsafeFormatAttributedFunctionCallGadget :
public WarningGadget {
2268 const CallExpr *
const Call;
2269 const Expr *UnsafeArg =
nullptr;
2270 constexpr static const char *
const Tag =
"UnsafeFormatAttributedFunctionCall";
2271 constexpr static const char *
const UnsafeStringTag =
2272 "UnsafeFormatAttributedFunctionCall_string";
2276 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2277 Call(
Result.getNodeAs<CallExpr>(Tag)),
2278 UnsafeArg(
Result.getNodeAs<Expr>(UnsafeStringTag)) {}
2280 static bool matches(
const Stmt *S, ASTContext &Ctx,
2281 const UnsafeBufferUsageHandler *Handler,
2285 auto *CE = dyn_cast<CallExpr>(S);
2286 if (!CE || !CE->getDirectCallee())
2288 const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
2292 const FormatAttr *Attr =
nullptr;
2293 bool IsPrintf =
false;
2294 bool AnyAttr = llvm::any_of(
2295 FD->specific_attrs<FormatAttr>(),
2296 [&Attr, &IsPrintf](
const FormatAttr *FA) ->
bool {
2297 if (const auto *II = FA->getType()) {
2298 if (II->getName() ==
"printf" || II->getName() ==
"scanf") {
2300 IsPrintf = II->getName() ==
"printf";
2306 const Expr *UnsafeArg;
2312 unsigned FmtIdx = Attr->getFormatIdx() - 1;
2313 std::optional<unsigned> FmtArgIdx = Attr->getFirstArg() - 1;
2323 }
else if (CE->getStmtClass() != Stmt::CallExprClass &&
2326 if (*FmtArgIdx >= CE->getNumArgs())
2333 FmtArgIdx = std::nullopt;
2335 if (AnyAttr && !IsPrintf && FmtArgIdx) {
2337 Result.addNode(Tag, DynTypedNode::create(*CE));
2342 Ctx, CE, UnsafeArg, FmtIdx, FmtArgIdx)) {
2343 Result.addNode(Tag, DynTypedNode::create(*CE));
2344 Result.addNode(UnsafeStringTag, DynTypedNode::create(*UnsafeArg));
2350 const Stmt *getBaseStmt()
const {
return Call; }
2355 bool IsRelatedToDecl,
2360 UnsafeLibcFunctionCallGadget::UnsafeKind::STRING |
2361 UnsafeLibcFunctionCallGadget::UnsafeKind::FORMAT_ATTR,
2366 UnsafeLibcFunctionCallGadget::UnsafeKind::OTHERS |
2367 UnsafeLibcFunctionCallGadget::UnsafeKind::FORMAT_ATTR,
2371 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2379class ULCArraySubscriptGadget :
public FixableGadget {
2381 static constexpr const char *
const ULCArraySubscriptTag =
2382 "ArraySubscriptUnderULC";
2383 const ArraySubscriptExpr *Node;
2387 : FixableGadget(
Kind::ULCArraySubscript),
2388 Node(
Result.getNodeAs<ArraySubscriptExpr>(ULCArraySubscriptTag)) {
2389 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2392 static bool classof(
const Gadget *G) {
2393 return G->getKind() == Kind::ULCArraySubscript;
2396 static bool matches(
const Stmt *S,
2397 llvm::SmallVectorImpl<MatchResult> &Results) {
2398 size_t SizeBefore = Results.size();
2400 const auto *ASE = dyn_cast<ArraySubscriptExpr>(E);
2406 !isSupportedVariable(*DRE))
2409 R.addNode(ULCArraySubscriptTag, DynTypedNode::create(*ASE));
2410 Results.emplace_back(std::move(R));
2412 return SizeBefore != Results.size();
2415 virtual std::optional<FixItList>
2416 getFixits(
const FixitStrategy &S)
const override;
2417 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2419 virtual DeclUseList getClaimedVarUseSites()
const override {
2420 if (
const auto *DRE =
2421 dyn_cast<DeclRefExpr>(Node->getBase()->IgnoreImpCasts())) {
2431class UPCStandalonePointerGadget :
public FixableGadget {
2433 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
2434 const DeclRefExpr *Node;
2438 : FixableGadget(
Kind::UPCStandalonePointer),
2439 Node(
Result.getNodeAs<DeclRefExpr>(DeclRefExprTag)) {
2440 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2443 static bool classof(
const Gadget *G) {
2444 return G->getKind() == Kind::UPCStandalonePointer;
2447 static bool matches(
const Stmt *S,
2448 llvm::SmallVectorImpl<MatchResult> &Results) {
2449 size_t SizeBefore = Results.size();
2451 auto *E = dyn_cast<Expr>(S);
2456 !isSupportedVariable(*DRE))
2459 R.addNode(DeclRefExprTag, DynTypedNode::create(*DRE));
2460 Results.emplace_back(std::move(R));
2462 return SizeBefore != Results.size();
2465 virtual std::optional<FixItList>
2466 getFixits(
const FixitStrategy &S)
const override;
2467 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2469 virtual DeclUseList getClaimedVarUseSites()
const override {
return {Node}; }
2472class PointerDereferenceGadget :
public FixableGadget {
2473 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2474 static constexpr const char *
const OperatorTag =
"op";
2476 const DeclRefExpr *BaseDeclRefExpr =
nullptr;
2477 const UnaryOperator *Op =
nullptr;
2481 : FixableGadget(
Kind::PointerDereference),
2482 BaseDeclRefExpr(
Result.getNodeAs<DeclRefExpr>(BaseDeclRefExprTag)),
2483 Op(
Result.getNodeAs<UnaryOperator>(OperatorTag)) {}
2485 static bool classof(
const Gadget *G) {
2486 return G->getKind() == Kind::PointerDereference;
2489 static bool matches(
const Stmt *S,
2490 llvm::SmallVectorImpl<MatchResult> &Results) {
2491 size_t SizeBefore = Results.size();
2493 const auto *UO = dyn_cast<UnaryOperator>(S);
2496 const auto *CE = dyn_cast<Expr>(UO->
getSubExpr());
2499 CE = CE->IgnoreParenImpCasts();
2500 const auto *DRE = dyn_cast<DeclRefExpr>(CE);
2501 if (!DRE || !isSupportedVariable(*DRE))
2504 R.addNode(BaseDeclRefExprTag, DynTypedNode::create(*DRE));
2505 R.addNode(OperatorTag, DynTypedNode::create(*UO));
2506 Results.emplace_back(std::move(R));
2508 return SizeBefore != Results.size();
2511 DeclUseList getClaimedVarUseSites()
const override {
2512 return {BaseDeclRefExpr};
2515 virtual std::optional<FixItList>
2516 getFixits(
const FixitStrategy &S)
const override;
2517 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2523class UPCAddressofArraySubscriptGadget :
public FixableGadget {
2525 static constexpr const char *
const UPCAddressofArraySubscriptTag =
2526 "AddressofArraySubscriptUnderUPC";
2527 const UnaryOperator *Node;
2531 : FixableGadget(
Kind::ULCArraySubscript),
2532 Node(
Result.getNodeAs<UnaryOperator>(UPCAddressofArraySubscriptTag)) {
2533 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2536 static bool classof(
const Gadget *G) {
2537 return G->getKind() == Kind::UPCAddressofArraySubscript;
2540 static bool matches(
const Stmt *S,
2541 llvm::SmallVectorImpl<MatchResult> &Results) {
2542 size_t SizeBefore = Results.size();
2544 auto *E = dyn_cast<Expr>(S);
2548 if (!UO || UO->
getOpcode() != UO_AddrOf)
2550 const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->
getSubExpr());
2555 if (!DRE || !isSupportedVariable(*DRE))
2558 R.addNode(UPCAddressofArraySubscriptTag, DynTypedNode::create(*UO));
2559 Results.emplace_back(std::move(R));
2561 return SizeBefore != Results.size();
2564 virtual std::optional<FixItList>
2565 getFixits(
const FixitStrategy &)
const override;
2566 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2568 virtual DeclUseList getClaimedVarUseSites()
const override {
2581class DeclUseTracker {
2582 using UseSetTy = llvm::SmallPtrSet<const DeclRefExpr *, 16>;
2583 using DefMapTy = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
2586 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
2590 DeclUseTracker() =
default;
2591 DeclUseTracker(
const DeclUseTracker &) =
delete;
2592 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
2593 DeclUseTracker(DeclUseTracker &&) =
default;
2594 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
2597 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
2600 void claimUse(
const DeclRefExpr *DRE) {
2601 assert(Uses->count(DRE) &&
2602 "DRE not found or claimed by multiple matchers!");
2607 bool hasUnclaimedUses(
const VarDecl *VD)
const {
2609 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
2614 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
2616 for (
auto use : *Uses) {
2618 ReturnSet.insert(use);
2624 void discoverDecl(
const DeclStmt *DS) {
2625 for (
const Decl *D : DS->
decls()) {
2626 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
2637 const DeclStmt *lookupDecl(
const VarDecl *VD)
const {
2638 return Defs.lookup(VD);
2647 static constexpr const char *
const UPCPreIncrementTag =
2648 "PointerPreIncrementUnderUPC";
2653 : FixableGadget(Kind::UPCPreIncrement),
2655 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2659 return G->getKind() == Kind::UPCPreIncrement;
2668 size_t SizeBefore = Results.size();
2670 auto *E = dyn_cast<Expr>(S);
2674 if (!UO || UO->
getOpcode() != UO_PreInc)
2676 const auto *DRE = dyn_cast<DeclRefExpr>(UO->
getSubExpr());
2677 if (!DRE || !isSupportedVariable(*DRE))
2681 Results.emplace_back(std::move(R));
2683 return SizeBefore != Results.size();
2686 virtual std::optional<FixItList>
2691 return {dyn_cast<DeclRefExpr>(Node->getSubExpr())};
2699 static constexpr const char *
const UUCAddAssignTag =
2700 "PointerAddAssignUnderUUC";
2701 static constexpr const char *
const OffsetTag =
"Offset";
2704 const Expr *Offset =
nullptr;
2708 : FixableGadget(Kind::UUCAddAssign),
2711 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2715 return G->getKind() == Kind::UUCAddAssign;
2720 size_t SizeBefore = Results.size();
2722 const auto *E = dyn_cast<Expr>(S);
2726 if (!BO || BO->
getOpcode() != BO_AddAssign)
2728 const auto *DRE = dyn_cast<DeclRefExpr>(BO->
getLHS());
2734 Results.emplace_back(std::move(R));
2736 return SizeBefore != Results.size();
2739 virtual std::optional<FixItList>
2744 return {dyn_cast<DeclRefExpr>(Node->getLHS())};
2751 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2752 static constexpr const char *
const DerefOpTag =
"DerefOp";
2753 static constexpr const char *
const AddOpTag =
"AddOp";
2754 static constexpr const char *
const OffsetTag =
"Offset";
2763 : FixableGadget(Kind::DerefSimplePtrArithFixable),
2771 auto IsPtr = [](
const Expr *E, MatchResult &R) {
2775 if (!DRE || !isSupportedVariable(*DRE))
2780 const auto IsPlusOverPtrAndInteger = [&IsPtr](
const Expr *E,
2782 const auto *BO = dyn_cast<BinaryOperator>(E);
2786 const auto *LHS = BO->
getLHS();
2787 const auto *RHS = BO->
getRHS();
2800 size_t SizeBefore = Results.size();
2801 const auto InnerMatcher = [&IsPlusOverPtrAndInteger,
2802 &Results](
const Expr *E) {
2803 const auto *UO = dyn_cast<UnaryOperator>(E);
2809 if (IsPlusOverPtrAndInteger(Operand, R)) {
2811 Results.emplace_back(std::move(R));
2815 return SizeBefore != Results.size();
2818 virtual std::optional<FixItList>
2821 return DerefOp->getBeginLoc();
2825 return {BaseDeclRefExpr};
2833 : WarningGadgets(WarningGadgets) {}
2842#define WARNING_GADGET(name) \
2843 if (name##Gadget::matches(S, Ctx, Result) && \
2844 notInSafeBufferOptOut(*S, &Handler)) { \
2845 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2848#define WARNING_OPTIONAL_GADGET(name) \
2849 if (name##Gadget::matches(S, Ctx, &Handler, Result) && \
2850 notInSafeBufferOptOut(*S, &Handler)) { \
2851 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2854#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2859 WarningGadgetList &WarningGadgets;
2866 DeclUseTracker &Tracker)
2867 : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
2871 bool matchFound =
false;
2878#define FIXABLE_GADGET(name) \
2879 if (name##Gadget::matches(S, Results)) { \
2880 for (const auto &R : Results) { \
2881 FixableGadgets.push_back(std::make_unique<name##Gadget>(R)); \
2882 matchFound = true; \
2886#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2889 if (
auto *DRE = findDeclRefExpr(S); DRE) {
2890 Tracker.discoverUse(DRE);
2896 if (
auto *DS = findDeclStmt(S); DS) {
2897 Tracker.discoverDecl(DS);
2905 const auto *DRE = dyn_cast<DeclRefExpr>(S);
2913 const DeclStmt *findDeclStmt(
const Stmt *S) {
2914 const auto *DS = dyn_cast<DeclStmt>(S);
2919 FixableGadgetList &FixableGadgets;
2920 DeclUseTracker &Tracker;
2926 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2927 WarningGadgetList &WarningGadgets,
2928 DeclUseTracker &Tracker) {
2931 if (EmitSuggestions) {
2940 return N1->getBeginLoc().getRawEncoding() <
2941 N2->getBeginLoc().getRawEncoding();
2951 const Expr *UnsafeArg =
nullptr)
override {}
2959 bool IsRelatedToDecl,
2980 FixableGadgetList FixableGadgets;
2981 WarningGadgetList WarningGadgets;
2982 DeclUseTracker Tracker;
2983 MockReporter IgnoreHandler;
2986 FixableGadgets, WarningGadgets, Tracker);
2988 std::set<const Expr *>
Result;
2989 for (
auto &G : WarningGadgets) {
2990 for (
const Expr *E : G->getUnsafePtrs()) {
2999 std::map<const VarDecl *, std::set<const WarningGadget *>,
3013 for (
auto &G : AllUnsafeOperations) {
3014 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
3016 bool AssociatedWithVarDecl =
false;
3017 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
3018 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3019 result.
byVar[VD].insert(G.get());
3020 AssociatedWithVarDecl =
true;
3024 if (!AssociatedWithVarDecl) {
3025 result.
noVar.push_back(G.get());
3033 std::map<const VarDecl *, std::set<const FixableGadget *>,
3043 for (
auto &F : AllFixableOperations) {
3044 DeclUseList DREs = F->getClaimedVarUseSites();
3047 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3048 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
3052 return FixablesForUnsafeVars;
3059 std::vector<const FixItHint *>
All;
3063 std::sort(
All.begin(),
All.end(),
3065 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
3066 H2->RemoveRange.getBegin());
3074 Hint->RemoveRange.getBegin())) {
3086std::optional<FixItList>
3087PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
3090 switch (S.
lookup(LeftVD)) {
3094 return std::nullopt;
3096 return std::nullopt;
3099 return std::nullopt;
3101 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3103 return std::nullopt;
3107static inline std::optional<FixItList>
createDataFixit(
const ASTContext &Ctx,
3108 const DeclRefExpr *DRE);
3110std::optional<FixItList>
3111CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
3130 if (S.
lookup(LeftVD) == FixitStrategy::Kind::Span) {
3131 if (S.
lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
3134 }
else if (S.
lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
3135 if (S.
lookup(RightVD) == FixitStrategy::Kind::Array) {
3139 return std::nullopt;
3142std::optional<FixItList>
3143PointerInitGadget::getFixits(
const FixitStrategy &S)
const {
3144 const auto *LeftVD = PtrInitLHS;
3146 switch (S.
lookup(LeftVD)) {
3147 case FixitStrategy::Kind::Span:
3148 if (S.
lookup(RightVD) == FixitStrategy::Kind::Span)
3150 return std::nullopt;
3151 case FixitStrategy::Kind::Wontfix:
3152 return std::nullopt;
3153 case FixitStrategy::Kind::Iterator:
3154 case FixitStrategy::Kind::Array:
3155 return std::nullopt;
3156 case FixitStrategy::Kind::Vector:
3157 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3159 return std::nullopt;
3165 if (ConstVal->isNegative())
3172std::optional<FixItList>
3173ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
3174 if (
const auto *DRE =
3176 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3178 case FixitStrategy::Kind::Span: {
3182 const ASTContext &Ctx =
3185 return std::nullopt;
3189 case FixitStrategy::Kind::Array:
3191 case FixitStrategy::Kind::Wontfix:
3192 case FixitStrategy::Kind::Iterator:
3193 case FixitStrategy::Kind::Vector:
3194 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3197 return std::nullopt;
3200static std::optional<FixItList>
3203std::optional<FixItList>
3204UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
3205 auto DREs = getClaimedVarUseSites();
3209 case FixitStrategy::Kind::Span:
3211 case FixitStrategy::Kind::Wontfix:
3212 case FixitStrategy::Kind::Iterator:
3213 case FixitStrategy::Kind::Array:
3214 return std::nullopt;
3215 case FixitStrategy::Kind::Vector:
3216 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3218 return std::nullopt;
3223 static const char *
const EOL =
"\n";
3230 std::string
s = std::string(
"<# ");
3231 s += HintTextToUser;
3237template <
typename NodeTy>
3238static std::optional<SourceLocation>
3241 if (
unsigned TkLen =
3248 return std::nullopt;
3261 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
3262 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
3263 VD->getBeginLoc())) &&
3264 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
3265 At->getRange().getBegin()));
3269 AttrRangeOverlapping;
3311 std::optional<Qualifiers> Quals = std::nullopt) {
3312 const char *
const SpanOpen =
"std::span<";
3315 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
3316 return SpanOpen + EltTyText.str() +
'>';
3319std::optional<FixItList>
3321 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->getDecl());
3326 if (
auto ConstVal = Offset->getIntegerConstantExpr(Ctx))
3327 if (ConstVal->isNegative())
3328 return std::nullopt;
3349 const Expr *LHS = AddOp->getLHS(), *RHS = AddOp->getRHS();
3356 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
3358 return std::nullopt;
3363 std::optional<SourceLocation> AddOpLocation =
3365 std::optional<SourceLocation> DerefOpLocation =
3368 if (!AddOpLocation || !DerefOpLocation)
3369 return std::nullopt;
3379 return std::nullopt;
3382std::optional<FixItList>
3383PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
3394 if (
auto LocPastOperand =
3401 case FixitStrategy::Kind::Iterator:
3402 case FixitStrategy::Kind::Array:
3403 return std::nullopt;
3404 case FixitStrategy::Kind::Vector:
3405 llvm_unreachable(
"FixitStrategy not implemented yet!");
3406 case FixitStrategy::Kind::Wontfix:
3407 llvm_unreachable(
"Invalid strategy!");
3410 return std::nullopt;
3417 std::optional<SourceLocation> EndOfOperand =
3423 return std::nullopt;
3428std::optional<FixItList>
3429UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
3432 case FixitStrategy::Kind::Array:
3433 case FixitStrategy::Kind::Span: {
3438 case FixitStrategy::Kind::Wontfix:
3439 case FixitStrategy::Kind::Iterator:
3440 return std::nullopt;
3441 case FixitStrategy::Kind::Vector:
3442 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3445 return std::nullopt;
3450static std::optional<FixItList>
3457 const Expr *Idx = ArraySub->getIdx();
3460 std::stringstream SS;
3461 bool IdxIsLitZero =
false;
3464 if ((*ICE).isZero())
3465 IdxIsLitZero =
true;
3466 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
3468 return std::nullopt;
3472 SS << (*DreString).str() <<
".data()";
3474 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
3476 return std::nullopt;
3478 SS <<
"&" << (*DreString).str() <<
".data()"
3479 <<
"[" << (*IndexString).str() <<
"]";
3485std::optional<FixItList>
3489 if (DREs.size() != 1)
3490 return std::nullopt;
3492 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3496 const Stmt *AddAssignNode = Node;
3497 StringRef varName = VD->
getName();
3501 return std::nullopt;
3505 (Offset->IgnoreParens()->getBeginLoc() == Offset->getBeginLoc());
3506 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
3510 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
3512 if (!AddAssignLocation)
3513 return std::nullopt;
3520 Offset->getEndLoc().getLocWithOffset(1),
")"));
3524 return std::nullopt;
3527std::optional<FixItList>
3531 if (DREs.size() != 1)
3532 return std::nullopt;
3534 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3537 std::stringstream SS;
3538 StringRef varName = VD->
getName();
3542 SS <<
"(" << varName.data() <<
" = " << varName.data()
3543 <<
".subspan(1)).data()";
3544 std::optional<SourceLocation> PreIncLocation =
3546 if (!PreIncLocation)
3547 return std::nullopt;
3550 SourceRange(Node->getBeginLoc(), *PreIncLocation), SS.str()));
3554 return std::nullopt;
3572static std::optional<FixItList>
3574 const StringRef UserFillPlaceHolder) {
3582 if (
Init->isNullPointerConstant(
3587 NPC_ValueDependentIsNotNull)) {
3588 std::optional<SourceLocation> InitLocation =
3591 return std::nullopt;
3599 std::string ExtentText = UserFillPlaceHolder.data();
3600 StringRef One =
"1";
3605 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
3610 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
3611 if (!Ext->HasSideEffects(Ctx)) {
3612 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
3614 return std::nullopt;
3615 ExtentText = *ExtentString;
3617 }
else if (!CxxNew->isArray())
3629 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
3630 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
3631 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
3638 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
3641 return std::nullopt;
3643 StrBuffer.append(
", ");
3644 StrBuffer.append(ExtentText);
3645 StrBuffer.append(
"}");
3651#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
3652 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
3653 "failed to produce fixit for declaration '" + \
3654 (D)->getNameAsString() + "'" + (Msg))
3656#define DEBUG_NOTE_DECL_FAIL(D, Msg)
3662static std::optional<std::string>
3666 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3671 return std::nullopt;
3673 std::string SpanTyText =
"std::span<";
3675 SpanTyText.append(*PteTyText);
3677 if (PteTyQualifiers) {
3678 SpanTyText.append(
" ");
3679 SpanTyText.append(PteTyQualifiers->getAsString());
3681 SpanTyText.append(
">");
3700 const StringRef UserFillPlaceHolder,
3714 std::stringstream SS;
3719 std::optional<FixItList> InitFixIts =
3723 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
3724 std::make_move_iterator(InitFixIts->end()));
3731 if (!EndLocForReplacement.
isValid()) {
3781static std::optional<FixItList>
3787 return std::nullopt;
3792 std::vector<std::string> NewTysTexts(NumParms);
3793 std::vector<bool> ParmsMask(NumParms,
false);
3794 bool AtLeastOneParmToFix =
false;
3796 for (
unsigned i = 0; i < NumParms; i++) {
3803 return std::nullopt;
3805 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3806 std::optional<std::string> PteTyText =
3811 return std::nullopt;
3815 ParmsMask[i] =
true;
3816 AtLeastOneParmToFix =
true;
3818 if (!AtLeastOneParmToFix)
3825 const auto NewOverloadSignatureCreator =
3826 [&
SM, &LangOpts, &NewTysTexts,
3827 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3828 std::stringstream SS;
3836 SS << Prefix->str();
3838 return std::nullopt;
3842 for (
unsigned i = 0; i < NumParms; i++) {
3850 SS << NewTysTexts[i];
3853 SS <<
' ' << II->getName().str();
3854 }
else if (
auto ParmTypeText =
3858 SS << ParmTypeText->str();
3860 return std::nullopt;
3861 if (i != NumParms - 1)
3870 const auto OldOverloadDefCreator =
3871 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3872 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3873 std::stringstream SS;
3881 << FDPrefix->str() <<
"{";
3883 return std::nullopt;
3886 SS <<
"return " << FunQualName->str() <<
"(";
3888 return std::nullopt;
3892 for (
unsigned i = 0; i < NumParms; i++) {
3901 return std::nullopt;
3908 if (i != NumParms - 1)
3919 std::optional<SourceLocation> Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3923 if (FReDecl->isThisDeclarationADefinition()) {
3924 assert(FReDecl == FD &&
"inconsistent function definition");
3927 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3933 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3936 FReDecl->getBeginLoc(),
" ")));
3939 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3961 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3977 std::stringstream SS;
3980 if (PteTyQualifiers)
3989 SS <<
' ' << PVDNameText->str();
3995 const DeclUseTracker &Tracker,
3998 const DeclStmt *DS = Tracker.lookupDecl(VD);
4001 " : variables declared this way not implemented yet");
4025 const QualType &ArrayEltT = CAT->getElementType();
4026 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
4035 auto MaybeElemTypeTxt =
4038 if (!MaybeElemTypeTxt)
4040 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
4045 while (NextTok && !NextTok->is(tok::l_square) &&
4058 if (!MaybeArraySizeTxt)
4060 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
4061 if (ArraySizeTxt.empty()) {
4072 std::optional<StringRef> IdentText =
4081 llvm::raw_svector_ostream OS(Replacement);
4082 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
4083 << IdentText->str();
4093 const DeclUseTracker &Tracker,
4096 const DeclStmt *DS = Tracker.lookupDecl(VD);
4097 assert(DS &&
"Fixing non-local variables not implemented yet!");
4116 const DeclUseTracker &Tracker,
ASTContext &Ctx,
4118 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
4119 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
4120 if (!FD || FD != D) {
4131 if (FD->isMain() || FD->isConstexpr() ||
4138 FD->isOverloadedOperator()) {
4147 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
4165 llvm_unreachable(
"FixitStrategy not implemented yet!");
4167 llvm_unreachable(
"Invalid strategy!");
4169 llvm_unreachable(
"Unknown strategy!");
4177 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
4179 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
4196 std::map<const VarDecl *, FixItList> &FixItsForVariable,
4201 for (
const auto &[VD, Ignore] : FixItsForVariable) {
4203 if (llvm::any_of(Grp,
4204 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
4205 return !FixItsForVariable.count(GrpMember);
4210 ToErase.push_back(
Member);
4213 for (
auto *VarToErase : ToErase)
4214 FixItsForVariable.erase(VarToErase);
4225 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
4229 FixItList FixItsSharedByParms{};
4231 std::optional<FixItList> OverloadFixes =
4234 if (OverloadFixes) {
4235 FixItsSharedByParms.append(*OverloadFixes);
4241 FixItsForVariable.erase(
Member);
4243 return FixItsSharedByParms;
4247static std::map<const VarDecl *, FixItList>
4256 std::map<const VarDecl *, FixItList> FixItsForVariable;
4261 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
4262 FixItsForVariable[VD] =
4266 if (FixItsForVariable[VD].empty()) {
4267 FixItsForVariable.erase(VD);
4270 for (
const auto &F : Fixables) {
4271 std::optional<FixItList> Fixits = F->getFixits(S);
4274 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
4275 Fixits->begin(), Fixits->end());
4280 VD, F->getSourceLoc(),
4281 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
4284 FixItsForVariable.erase(VD);
4303 FixItList FixItsSharedByParms{};
4305 if (
auto *FD = dyn_cast<FunctionDecl>(D))
4307 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
4311 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
4314 for (
auto &[Var, Ignore] : FixItsForVariable) {
4315 bool AnyParm =
false;
4316 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
4318 for (
const VarDecl *GrpMate : VarGroupForVD) {
4321 if (FixItsForVariable.count(GrpMate))
4322 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
4326 assert(!FixItsSharedByParms.empty() &&
4327 "Should not try to fix a parameter that does not belong to a "
4329 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
4336 for (
auto Iter = FinalFixItsForVariable.begin();
4337 Iter != FinalFixItsForVariable.end();)
4340 Iter = FinalFixItsForVariable.erase(Iter);
4343 return FinalFixItsForVariable;
4346template <
typename VarDeclIterTy>
4350 for (
const VarDecl *VD : UnsafeVars) {
4361 const std::vector<VarGrpTy> &Groups;
4362 const std::map<const VarDecl *, unsigned> &VarGrpMap;
4363 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
4367 const std::vector<VarGrpTy> &Groups,
4368 const std::map<const VarDecl *, unsigned> &VarGrpMap,
4369 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
4370 : Groups(Groups), VarGrpMap(VarGrpMap),
4371 GrpsUnionForParms(GrpsUnionForParms) {}
4374 if (GrpsUnionForParms.contains(Var)) {
4377 return GrpsUnionForParms.getArrayRef();
4382 auto It = VarGrpMap.find(Var);
4384 if (It == VarGrpMap.end())
4386 return Groups[It->second];
4390 return GrpsUnionForParms.getArrayRef();
4395 WarningGadgetList WarningGadgets,
4396 DeclUseTracker Tracker,
4398 bool EmitSuggestions) {
4399 if (!EmitSuggestions) {
4403 for (
const auto &G : WarningGadgets) {
4404 G->handleUnsafeOperation(Handler,
false,
4410 assert(FixableGadgets.empty() &&
4411 "Fixable gadgets found but suggestions not requested!");
4417 if (!WarningGadgets.empty()) {
4421 for (
const auto &G : FixableGadgets) {
4422 for (
const auto *DRE : G->getClaimedVarUseSites()) {
4423 Tracker.claimUse(DRE);
4439 if (WarningGadgets.empty())
4447 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
4450 for (
auto it = FixablesForAllVars.
byVar.cbegin();
4451 it != FixablesForAllVars.
byVar.cend();) {
4456 (
"failed to produce fixit for '" +
4457 it->first->getNameAsString() +
4458 "' : neither local nor a parameter"));
4460 it = FixablesForAllVars.
byVar.erase(it);
4461 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
4464 (
"failed to produce fixit for '" +
4465 it->first->getNameAsString() +
4466 "' : has a reference type"));
4468 it = FixablesForAllVars.
byVar.erase(it);
4469 }
else if (Tracker.hasUnclaimedUses(it->first)) {
4470 it = FixablesForAllVars.
byVar.erase(it);
4471 }
else if (it->first->isInitCapture()) {
4474 (
"failed to produce fixit for '" +
4475 it->first->getNameAsString() +
4476 "' : init capture"));
4478 it = FixablesForAllVars.
byVar.erase(it);
4485 for (
const auto &it : UnsafeOps.
byVar) {
4486 const VarDecl *
const UnsafeVD = it.first;
4487 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
4488 if (UnclaimedDREs.empty())
4492 std::string UnclaimedUseTrace =
4497 (
"failed to produce fixit for '" + UnfixedVDName +
4498 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
4499 UnclaimedUseTrace));
4506 llvm::DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
4507 DepMapTy DependenciesMap{};
4508 DepMapTy PtrAssignmentGraph{};
4510 for (
const auto &it : FixablesForAllVars.
byVar) {
4511 for (
const FixableGadget *fixable : it.second) {
4512 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
4513 fixable->getStrategyImplications();
4515 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
4516 PtrAssignmentGraph[Impl.first].insert(Impl.second);
4538 std::set<const VarDecl *> VisitedVarsDirected{};
4539 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4540 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
4542 std::queue<const VarDecl *> QueueDirected{};
4543 QueueDirected.push(Var);
4544 while (!QueueDirected.empty()) {
4545 const VarDecl *CurrentVar = QueueDirected.front();
4546 QueueDirected.pop();
4547 VisitedVarsDirected.insert(CurrentVar);
4548 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
4549 for (
const VarDecl *Adj : AdjacentNodes) {
4550 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
4551 QueueDirected.push(Adj);
4553 DependenciesMap[Var].insert(Adj);
4554 DependenciesMap[Adj].insert(Var);
4561 std::vector<VarGrpTy> Groups;
4565 std::map<const VarDecl *, unsigned> VarGrpMap;
4567 llvm::SetVector<const VarDecl *>
4572 std::set<const VarDecl *> VisitedVars{};
4573 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4574 if (VisitedVars.find(Var) == VisitedVars.end()) {
4575 VarGrpTy &VarGroup = Groups.emplace_back();
4576 std::queue<const VarDecl *> Queue{};
4579 while (!Queue.empty()) {
4580 const VarDecl *CurrentVar = Queue.front();
4582 VisitedVars.insert(CurrentVar);
4583 VarGroup.push_back(CurrentVar);
4584 auto AdjacentNodes = DependenciesMap[CurrentVar];
4585 for (
const VarDecl *Adj : AdjacentNodes) {
4586 if (VisitedVars.find(Adj) == VisitedVars.end()) {
4592 bool HasParm =
false;
4593 unsigned GrpIdx = Groups.size() - 1;
4595 for (
const VarDecl *
V : VarGroup) {
4596 VarGrpMap[
V] = GrpIdx;
4601 GrpsUnionForParms.insert_range(VarGroup);
4623 for (
auto I = FixablesForAllVars.
byVar.begin();
4624 I != FixablesForAllVars.
byVar.end();) {
4626 if (!VisitedVars.count((*I).first)) {
4628 I = FixablesForAllVars.
byVar.erase(I);
4636 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
4638 return FixablesForAllVars.
byVar.count(
V);
4645 FixItsForVariableGroup =
4647 Tracker, Handler, VarGrpMgr);
4649 for (
const auto &G : UnsafeOps.
noVar) {
4650 G->handleUnsafeOperation(Handler,
false,
4654 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
4655 auto FixItsIt = FixItsForVariableGroup.find(VD);
4657 FixItsIt != FixItsForVariableGroup.end()
4658 ? std::move(FixItsIt->second)
4661 for (
const auto &G : WarningGadgets) {
4662 G->handleUnsafeOperation(Handler,
true,
4670 bool EmitSuggestions) {
4679 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
4682 if (FD->isConsteval())
4687 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
4688 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
4693 if (FReDecl->isExternC()) {
4696 EmitSuggestions =
false;
4701 Stmts.push_back(FD->getBody());
4703 if (
const auto *ID = dyn_cast<CXXConstructorDecl>(D)) {
4705 Stmts.push_back(CI->getInit());
4709 Stmts.push_back(D->
getBody());
4712 assert(!Stmts.empty());
4714 FixableGadgetList FixableGadgets;
4715 WarningGadgetList WarningGadgets;
4716 DeclUseTracker Tracker;
4717 for (
Stmt *S : Stmts) {
4719 WarningGadgets, Tracker);
4721 applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
4722 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.