29#include "llvm/ADT/APInt.h"
30#include "llvm/ADT/APSInt.h"
31#include "llvm/ADT/STLFunctionalExtras.h"
32#include "llvm/ADT/SmallVector.h"
33#include "llvm/ADT/StringRef.h"
49 std::string VisitBinaryOperator(
const BinaryOperator *BO) {
50 return "BinaryOperator(" + BO->
getOpcodeStr().str() +
")";
53 std::string VisitUnaryOperator(
const UnaryOperator *UO) {
57 std::string VisitImplicitCastExpr(
const ImplicitCastExpr *ICE) {
64static std::string getDREAncestorString(
const DeclRefExpr *DRE,
68 StmtDebugPrinter StmtPriner;
71 SS << StmtPriner.Visit(St);
75 if (StParents.
size() > 1)
76 return "unavailable due to multiple parents";
77 if (StParents.
empty())
96 virtual bool matches(
const DynTypedNode &DynNode, ASTContext &Ctx,
97 const UnsafeBufferUsageHandler &Handler) = 0;
98 virtual ~FastMatcher() =
default;
104 template <
typename T>
const T *getNodeAs(StringRef ID)
const {
105 auto It =
Nodes.find(ID);
106 if (It ==
Nodes.end()) {
109 return It->second.get<
T>();
112 void addNode(StringRef ID,
const DynTypedNode &Node) {
Nodes[
ID] = Node; }
115 llvm::StringMap<DynTypedNode>
Nodes;
119#define SIZED_CONTAINER_OR_VIEW_LIST \
120 "span", "array", "vector", "basic_string_view", "basic_string", \
131 bool FindAll,
bool IgnoreUnevaluatedContext,
133 : Matcher(&Matcher), FindAll(FindAll), Matches(
false),
134 IgnoreUnevaluatedContext(IgnoreUnevaluatedContext),
135 ActiveASTContext(&Context), Handler(&NewHandler) {
172 if (IgnoreUnevaluatedContext)
174 return DynamicRecursiveASTVisitor::TraverseGenericSelectionExpr(Node);
180 if (IgnoreUnevaluatedContext)
182 return DynamicRecursiveASTVisitor::TraverseUnaryExprOrTypeTraitExpr(Node);
186 bool TraverseQualifier)
override {
188 if (IgnoreUnevaluatedContext)
190 return DynamicRecursiveASTVisitor::TraverseTypeOfExprTypeLoc(
191 Node, TraverseQualifier);
195 bool TraverseQualifier)
override {
197 if (IgnoreUnevaluatedContext)
199 return DynamicRecursiveASTVisitor::TraverseDecltypeTypeLoc(
200 Node, TraverseQualifier);
205 if (IgnoreUnevaluatedContext)
207 return DynamicRecursiveASTVisitor::TraverseCXXNoexceptExpr(Node);
212 if (IgnoreUnevaluatedContext)
214 return DynamicRecursiveASTVisitor::TraverseCXXTypeidExpr(Node);
220 return DynamicRecursiveASTVisitor::TraverseCXXDefaultInitExpr(Node);
236 template <
typename T>
bool match(
const T &Node) {
246 FastMatcher *
const Matcher;
250 bool IgnoreUnevaluatedContext;
251 ASTContext *ActiveASTContext;
252 const UnsafeBufferUsageHandler *Handler;
267 FastMatcher &Matcher) {
275 FastMatcher &Matcher) {
303 const Stmt *S,
const llvm::function_ref<
void(
const Expr *)> OnResult) {
304 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(S);
305 CE && CE->getCastKind() == CastKind::CK_LValueToRValue)
306 OnResult(CE->getSubExpr());
307 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
315 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
324 if (
auto *CE = dyn_cast<CallExpr>(S)) {
325 if (
const auto *FnDecl = CE->getDirectCallee();
326 FnDecl && FnDecl->hasAttr<UnsafeBufferUsageAttr>())
335 if (
auto *CE = dyn_cast<CastExpr>(S)) {
336 if (CE->getCastKind() != CastKind::CK_PointerToIntegral &&
337 CE->getCastKind() != CastKind::CK_PointerToBoolean)
341 InnerMatcher(CE->getSubExpr());
345 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
359 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
365 InnerMatcher(BO->
getLHS());
366 InnerMatcher(BO->
getRHS());
384 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
389 if (
auto *CS = dyn_cast<CompoundStmt>(S)) {
390 for (
auto *Child : CS->body())
393 if (
auto *IfS = dyn_cast<IfStmt>(S)) {
395 InnerMatcher(IfS->getThen());
397 InnerMatcher(IfS->getElse());
448 case Stmt::DeclRefExprClass:
450 case Stmt::BinaryOperatorClass: {
453 BO2->getLHS(), BO2->getOpcode(),
479 dyn_cast<CXXMemberCallExpr>(Size->IgnoreParenImpCasts())) {
480 auto *DREOfPtr = dyn_cast<DeclRefExpr>(
481 MCEPtr->getImplicitObjectArgument()->IgnoreParenImpCasts());
482 auto *DREOfSize = dyn_cast<DeclRefExpr>(
483 MCESize->getImplicitObjectArgument()->IgnoreParenImpCasts());
485 if (!DREOfPtr || !DREOfSize)
489 if (DREOfPtr->getDecl() != DREOfSize->getDecl())
491 if (MCEPtr->getMethodDecl()->getName() !=
"data")
494 if (!MCEPtr->getRecordDecl()->isInStdNamespace())
497 auto *ObjII = MCEPtr->getRecordDecl()->getIdentifier();
504 if (!((AcceptSizeBytes &&
505 MCESize->getMethodDecl()->getName() ==
"size_bytes") ||
510 MCESize->getMethodDecl()->getName() ==
"size"))
520 if (Size->EvaluateAsInt(ER, Ctx)) {
526 return llvm::APSInt::compareValues(
527 SizeInt, llvm::APSInt(CAT->getSize(),
true)) == 0;
535 return UO && UO->
getOpcode() == UnaryOperator::Opcode::UO_AddrOf;
537 auto *FnDecl = CE->getDirectCallee();
539 return FnDecl && FnDecl->getNameAsString() ==
"addressof" &&
540 FnDecl->isInStdNamespace();
568 "expecting a two-parameter std::span constructor");
571 auto HaveEqualConstantValues = [&Ctx](
const Expr *E0,
const Expr *E1) {
573 if (
auto E1CV = E1->getIntegerConstantExpr(Ctx)) {
574 return llvm::APSInt::compareValues(*E0CV, *E1CV) == 0;
578 auto AreSameDRE = [](
const Expr *E0,
const Expr *E1) {
579 if (
auto *DRE0 = dyn_cast<DeclRefExpr>(E0))
580 if (
auto *DRE1 = dyn_cast<DeclRefExpr>(E1)) {
581 return DRE0->getDecl() == DRE1->getDecl();
587 if (Arg1CV && Arg1CV->isZero())
593 case Stmt::CXXNewExprClass:
596 return AreSameDRE((*Size)->IgnoreImplicit(), Arg1) ||
597 HaveEqualConstantValues(*Size, Arg1);
602 return Arg1CV && Arg1CV->isOne();
610 if (
auto CCast = dyn_cast<CStyleCastExpr>(Arg0)) {
611 if (!CCast->getType()->isPointerType())
619 if (
const auto *
Call = dyn_cast<CallExpr>(CCast->getSubExpr())) {
621 if (
auto *AllocAttr = FD->getAttr<AllocSizeAttr>()) {
622 const Expr *EleSizeExpr =
623 Call->getArg(AllocAttr->getElemSizeParam().getASTIndex());
625 ParamIdx NumElemIdx = AllocAttr->getNumElemsParam();
632 if (
auto BO = dyn_cast<BinaryOperator>(Arg1))
639 auto IsMethodCallToSizedObject = [](
const Stmt *Node, StringRef MethodName) {
640 if (
const auto *MC = dyn_cast<CXXMemberCallExpr>(Node)) {
641 const auto *MD = MC->getMethodDecl();
642 const auto *RD = MC->getRecordDecl();
645 if (
auto *II = RD->getDeclName().getAsIdentifierInfo();
646 II && RD->isInStdNamespace())
649 MD->getName() == MethodName;
654 if (IsMethodCallToSizedObject(Arg0,
"begin") &&
655 IsMethodCallToSizedObject(Arg1,
"end"))
659 ->getImplicitObjectArgument()
660 ->IgnoreParenImpCasts(),
662 ->getImplicitObjectArgument()
663 ->IgnoreParenImpCasts());
671 const bool IgnoreStaticSizedArrays) {
680 if (
const auto *CATy =
681 dyn_cast<ConstantArrayType>(Node.
getBase()
685 limit = CATy->getLimitedSize();
686 }
else if (
const auto *SLiteral = dyn_cast<clang::StringLiteral>(
688 limit = SLiteral->getLength() + 1;
693 if (IgnoreStaticSizedArrays) {
703 llvm::APSInt ArrIdx = EVResult.
Val.
getInt();
706 if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit)
708 }
else if (
const auto *BE = dyn_cast<BinaryOperator>(IndexExpr)) {
711 if (BE->getOpcode() != BO_And && BE->getOpcode() != BO_Rem)
714 const Expr *LHS = BE->getLHS();
715 const Expr *RHS = BE->getRHS();
717 if (BE->getOpcode() == BO_Rem) {
724 llvm::APSInt result = EVResult.
Val.
getInt();
725 if (result.isNonNegative() && result.getLimitedValue() <= limit)
736 llvm::APSInt result = EVResult.
Val.
getInt();
737 if (result.isNonNegative() && result.getLimitedValue() < limit)
751 if (
const auto *CE = dyn_cast<ConditionalOperator>(E)) {
753 const auto *
Cond = CE->getCond();
755 if (!
Cond->isValueDependent() &&
756 Cond->EvaluateAsBooleanCondition(CondEval, Ctx))
757 return CondEval ? CE->getLHS() : CE->getRHS();
766 if (
const auto *DefaultArgE = dyn_cast<CXXDefaultArgExpr>(Ptr))
767 Ptr = DefaultArgE->getExpr();
783 static const llvm::StringSet<> NullTermFunctions = {
"strerror"};
808 StringRef
matchName(StringRef FunName,
bool isBuiltin) {
810 if (isBuiltin && FunName.starts_with(
"__builtin_"))
814 FunName.drop_front(10 ));
816 if (FunName.starts_with(
"__asan_"))
824 if (Name.starts_with(
"__") && Name.ends_with(
"_chk"))
826 Name.drop_front(2).drop_back(4) );
831 if (Name.ends_with(
"_s"))
832 return Name.drop_back(2 );
849 const Expr *&UnsafeArg,
const unsigned FmtIdx,
850 std::optional<const unsigned> FmtArgIdx = std::nullopt,
851 bool isKprintf =
false) {
852 class StringFormatStringHandler
856 const Expr *&UnsafeArg;
872 unsigned PArgIdx = Precision.
getArgIndex() + FmtArgIdx;
874 if (PArgIdx < Call->getNumArgs()) {
875 const Expr *PArg =
Call->getArg(PArgIdx);
878 if (
auto *CE = dyn_cast<CastExpr>(PArg);
879 CE && CE->getType()->isSignedIntegerType())
880 PArg = CE->getSubExpr();
885 analyze_printf::OptionalAmount::HowSpecified::Constant) {
887 llvm::APSInt PArgVal = llvm::APSInt(
897 StringFormatStringHandler(
const CallExpr *
Call,
unsigned FmtArgIdx,
899 :
Call(
Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx),
900 UnsafeArgSet(
false) {}
903 const char *startSpecifier,
904 unsigned specifierLen,
912 if (ArgIdx >=
Call->getNumArgs())
916 const Expr *Arg =
Call->getArg(ArgIdx);
926 bool IsArgTypeValid =
929 ?
ArgType->getPointeeType()->isWideCharType()
930 :
ArgType->getPointeeType()->isCharType());
933 Precision && IsArgTypeValid)
937 UnsafeArg =
Call->getArg(ArgIdx);
942 bool isUnsafeArgSet() {
return UnsafeArgSet; }
945 const Expr *Fmt =
Call->getArg(FmtIdx);
946 unsigned FmtArgStartingIdx =
947 FmtArgIdx.has_value() ?
static_cast<unsigned>(*FmtArgIdx) : FmtIdx + 1;
950 if (SL->getCharByteWidth() == 1) {
951 StringRef FmtStr = SL->getString();
952 StringFormatStringHandler Handler(
Call, FmtArgStartingIdx, UnsafeArg,
956 Handler, FmtStr.begin(), FmtStr.end(), Ctx.
getLangOpts(),
958 Handler.isUnsafeArgSet();
961 if (
auto FmtStr = SL->tryEvaluateString(Ctx)) {
962 StringFormatStringHandler Handler(
Call, FmtArgStartingIdx, UnsafeArg,
965 Handler, FmtStr->data(), FmtStr->data() + FmtStr->size(),
967 Handler.isUnsafeArgSet();
974 llvm::make_range(
Call->arg_begin() + FmtIdx,
Call->arg_end()),
975 [&UnsafeArg, &Ctx](
const Expr *Arg) ->
bool {
976 if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg, Ctx)) {
994 static std::unique_ptr<std::set<StringRef>> PredefinedNames =
nullptr;
995 if (!PredefinedNames)
997 std::make_unique<std::set<StringRef>, std::set<StringRef>>({
1078 if (PredefinedNames->find(Name) != PredefinedNames->end())
1081 std::string NameWCS = Name.str();
1082 size_t WcsPos = NameWCS.find(
"wcs");
1084 while (WcsPos != std::string::npos) {
1085 NameWCS[WcsPos++] =
's';
1086 NameWCS[WcsPos++] =
't';
1087 NameWCS[WcsPos++] =
'r';
1088 WcsPos = NameWCS.find(
"wcs", WcsPos);
1090 if (PredefinedNames->find(NameWCS) != PredefinedNames->end())
1094 return Name.ends_with(
"scanf");
1109 if (!Name.ends_with(
"printf"))
1111 return Name.starts_with(
"v");
1125 if (!Name.ends_with(
"printf") ||
1127 Name.starts_with(
"v"))
1130 StringRef Prefix = Name.drop_back(6);
1132 if (Prefix.ends_with(
"w"))
1133 Prefix = Prefix.drop_back(1);
1134 return Prefix ==
"s";
1149 if (!Name.ends_with(
"printf") || Name.starts_with(
"v"))
1152 StringRef Prefix = Name.drop_back(6);
1154 if (Prefix.ends_with(
"w"))
1155 Prefix = Prefix.drop_back(1);
1157 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
1165 MatchResult &Result, llvm::StringRef Tag) {
1169 assert(FD &&
"It should have been checked that FD is non-null.");
1187 const Expr *UnsafeArg;
1198 bool isKprintf =
false;
1199 const Expr *UnsafeArg;
1202 isKprintf = II->getName() ==
"kprintf";
1204 std::nullopt, isKprintf)) {
1217 const Expr *UnsafeArg;
1228 for (
const auto *Arg : Node.
arguments())
1243 assert(FD &&
"It should have been checked that FD is non-null.");
1258 !Size->getType()->isUnsignedIntegerType())
1287#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1290 Gadget(Kind K) : K(K) {}
1292 Kind
getKind()
const {
return K; }
1295 StringRef getDebugName()
const {
1300#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1302 llvm_unreachable(
"Unhandled Gadget::Kind enum");
1306 virtual bool isWarningGadget()
const = 0;
1309 virtual SourceLocation getSourceLoc()
const = 0;
1314 virtual DeclUseList getClaimedVarUseSites()
const = 0;
1316 virtual ~Gadget() =
default;
1324class WarningGadget :
public Gadget {
1326 WarningGadget(Kind K) : Gadget(K) {}
1328 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1329 bool isWarningGadget() const final {
return true; }
1331 virtual void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1332 bool IsRelatedToDecl,
1333 ASTContext &Ctx)
const = 0;
1335 virtual SmallVector<const Expr *, 1> getUnsafePtrs()
const = 0;
1342class FixableGadget :
public Gadget {
1344 FixableGadget(Kind K) : Gadget(K) {}
1346 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1347 bool isWarningGadget() const final {
return false; }
1352 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1353 return std::nullopt;
1362 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1363 getStrategyImplications()
const {
1364 return std::nullopt;
1368static bool isSupportedVariable(
const DeclRefExpr &Node) {
1380 dyn_cast<ClassTemplateSpecializationDecl>(
RecordDecl);
1381 if (!class_template_specialization_decl)
1386 if (template_args.
size() == 0)
1397class UniquePtrArrayAccessGadget :
public WarningGadget {
1399 static constexpr const char *
const AccessorTag =
"unique_ptr_array_access";
1400 const CXXOperatorCallExpr *AccessorExpr;
1404 : WarningGadget(
Kind::UniquePtrArrayAccess),
1405 AccessorExpr(
Result.getNodeAs<CXXOperatorCallExpr>(AccessorTag)) {
1406 assert(AccessorExpr &&
1407 "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr");
1410 static bool classof(
const Gadget *G) {
1411 return G->getKind() == Kind::UniquePtrArrayAccess;
1414 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1417 const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(S);
1418 if (!OpCall || OpCall->
getOperator() != OO_Subscript)
1425 const CXXMethodDecl *
Method =
1430 if (
Method->getOverloadedOperator() != OO_Subscript)
1434 if (!isUniquePtrArray(RecordDecl))
1437 const Expr *IndexExpr = OpCall->
getArg(1);
1438 clang::Expr::EvalResult Eval;
1444 Result.addNode(AccessorTag, DynTypedNode::create(*OpCall));
1447 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1448 bool IsRelatedToDecl,
1449 ASTContext &Ctx)
const override {
1451 DynTypedNode::create(*AccessorExpr), IsRelatedToDecl, Ctx);
1454 SourceLocation getSourceLoc()
const override {
1456 return AccessorExpr->getOperatorLoc();
1457 return SourceLocation();
1460 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1461 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1464using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1465using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1469class IncrementGadget :
public WarningGadget {
1470 static constexpr const char *
const OpTag =
"op";
1471 const UnaryOperator *Op;
1475 : WarningGadget(
Kind::Increment),
1476 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1478 static bool classof(
const Gadget *G) {
1479 return G->getKind() == Kind::Increment;
1482 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1484 const auto *UO = dyn_cast<UnaryOperator>(S);
1489 Result.addNode(OpTag, DynTypedNode::create(*UO));
1493 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1494 bool IsRelatedToDecl,
1495 ASTContext &Ctx)
const override {
1498 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1500 DeclUseList getClaimedVarUseSites()
const override {
1501 SmallVector<const DeclRefExpr *, 2> Uses;
1502 if (
const auto *DRE =
1503 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1504 Uses.push_back(DRE);
1507 return std::move(Uses);
1510 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1511 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1517class DecrementGadget :
public WarningGadget {
1518 static constexpr const char *
const OpTag =
"op";
1519 const UnaryOperator *Op;
1523 : WarningGadget(
Kind::Decrement),
1524 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1526 static bool classof(
const Gadget *G) {
1527 return G->getKind() == Kind::Decrement;
1530 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1532 const auto *UO = dyn_cast<UnaryOperator>(S);
1537 Result.addNode(OpTag, DynTypedNode::create(*UO));
1541 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1542 bool IsRelatedToDecl,
1543 ASTContext &Ctx)
const override {
1546 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1548 DeclUseList getClaimedVarUseSites()
const override {
1549 if (
const auto *DRE =
1550 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1557 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1558 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1564class ArraySubscriptGadget :
public WarningGadget {
1565 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1566 const ArraySubscriptExpr *ASE;
1571 ASE(
Result.getNodeAs<ArraySubscriptExpr>(ArraySubscrTag)) {}
1573 static bool classof(
const Gadget *G) {
1574 return G->getKind() == Kind::ArraySubscript;
1577 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1578 const UnsafeBufferUsageHandler *Handler,
1580 const auto *ASE = dyn_cast<ArraySubscriptExpr>(S);
1583 const auto *
const Base = ASE->getBase()->IgnoreParenImpCasts();
1586 const auto *Idx = dyn_cast<IntegerLiteral>(ASE->getIdx());
1587 bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
1594 Result.addNode(ArraySubscrTag, DynTypedNode::create(*ASE));
1598 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1599 bool IsRelatedToDecl,
1600 ASTContext &Ctx)
const override {
1603 SourceLocation getSourceLoc()
const override {
return ASE->getBeginLoc(); }
1605 DeclUseList getClaimedVarUseSites()
const override {
1606 if (
const auto *DRE =
1607 dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
1614 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1615 return {ASE->getBase()->IgnoreParenImpCasts()};
1623class PointerArithmeticGadget :
public WarningGadget {
1624 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1625 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1626 const BinaryOperator *PA;
1631 : WarningGadget(
Kind::PointerArithmetic),
1632 PA(
Result.getNodeAs<BinaryOperator>(PointerArithmeticTag)),
1633 Ptr(
Result.getNodeAs<Expr>(PointerArithmeticPointerTag)) {}
1635 static bool classof(
const Gadget *G) {
1636 return G->getKind() == Kind::PointerArithmetic;
1639 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1641 const auto *BO = dyn_cast<BinaryOperator>(S);
1644 const auto *LHS = BO->
getLHS();
1645 const auto *RHS = BO->
getRHS();
1650 RHS->getType()->isEnumeralType())) {
1651 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*LHS));
1652 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1658 (LHS->getType()->isIntegerType() || LHS->getType()->isEnumeralType())) {
1659 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*RHS));
1660 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1666 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1667 bool IsRelatedToDecl,
1668 ASTContext &Ctx)
const override {
1671 SourceLocation getSourceLoc()
const override {
return PA->getBeginLoc(); }
1673 DeclUseList getClaimedVarUseSites()
const override {
1674 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts())) {
1681 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1682 return {Ptr->IgnoreParenImpCasts()};
1689class SpanTwoParamConstructorGadget :
public WarningGadget {
1690 static constexpr const char *
const SpanTwoParamConstructorTag =
1691 "spanTwoParamConstructor";
1692 const CXXConstructExpr *Ctor;
1696 : WarningGadget(
Kind::SpanTwoParamConstructor),
1697 Ctor(
Result.getNodeAs<CXXConstructExpr>(SpanTwoParamConstructorTag)) {}
1699 static bool classof(
const Gadget *G) {
1700 return G->getKind() == Kind::SpanTwoParamConstructor;
1704 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1707 const auto *CDecl = CE->getConstructor();
1708 const auto *CRecordDecl = CDecl->getParent();
1709 auto HasTwoParamSpanCtorDecl =
1710 CRecordDecl->isInStdNamespace() &&
1711 CDecl->getDeclName().getAsString() ==
"span" && CE->getNumArgs() == 2;
1714 Result.addNode(SpanTwoParamConstructorTag, DynTypedNode::create(*CE));
1718 static bool matches(
const Stmt *S, ASTContext &Ctx,
1719 const UnsafeBufferUsageHandler *Handler,
1726 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1727 bool IsRelatedToDecl,
1728 ASTContext &Ctx)
const override {
1731 SourceLocation getSourceLoc()
const override {
return Ctor->getBeginLoc(); }
1733 DeclUseList getClaimedVarUseSites()
const override {
1736 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->getArg(0))) {
1743 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1750class PointerInitGadget :
public FixableGadget {
1752 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1753 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1754 const VarDecl *PtrInitLHS;
1755 const DeclRefExpr *PtrInitRHS;
1759 : FixableGadget(
Kind::PointerInit),
1760 PtrInitLHS(
Result.getNodeAs<VarDecl>(PointerInitLHSTag)),
1761 PtrInitRHS(
Result.getNodeAs<DeclRefExpr>(PointerInitRHSTag)) {}
1763 static bool classof(
const Gadget *G) {
1764 return G->getKind() == Kind::PointerInit;
1767 static bool matches(
const Stmt *S,
1768 llvm::SmallVectorImpl<MatchResult> &Results) {
1769 const DeclStmt *DS = dyn_cast<DeclStmt>(S);
1778 const auto *DRE = dyn_cast<DeclRefExpr>(
Init->IgnoreImpCasts());
1779 if (!DRE || !
hasPointerType(*DRE) || !isSupportedVariable(*DRE)) {
1783 R.addNode(PointerInitLHSTag, DynTypedNode::create(*VD));
1784 R.addNode(PointerInitRHSTag, DynTypedNode::create(*DRE));
1785 Results.emplace_back(std::move(R));
1789 virtual std::optional<FixItList>
1790 getFixits(
const FixitStrategy &S)
const override;
1791 SourceLocation getSourceLoc()
const override {
1792 return PtrInitRHS->getBeginLoc();
1795 virtual DeclUseList getClaimedVarUseSites()
const override {
1796 return DeclUseList{PtrInitRHS};
1799 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1800 getStrategyImplications()
const override {
1801 return std::make_pair(PtrInitLHS,
cast<VarDecl>(PtrInitRHS->getDecl()));
1810class PtrToPtrAssignmentGadget :
public FixableGadget {
1812 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1813 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1814 const DeclRefExpr *PtrLHS;
1815 const DeclRefExpr *PtrRHS;
1819 : FixableGadget(
Kind::PtrToPtrAssignment),
1820 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1821 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1823 static bool classof(
const Gadget *G) {
1824 return G->getKind() == Kind::PtrToPtrAssignment;
1827 static bool matches(
const Stmt *S,
1828 llvm::SmallVectorImpl<MatchResult> &Results) {
1829 size_t SizeBefore = Results.size();
1831 const auto *BO = dyn_cast<BinaryOperator>(S);
1832 if (!BO || BO->
getOpcode() != BO_Assign)
1835 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1837 !isSupportedVariable(*RHSRef)) {
1840 const auto *LHS = BO->
getLHS();
1841 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1843 !isSupportedVariable(*LHSRef)) {
1847 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1848 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1849 Results.emplace_back(std::move(R));
1851 return SizeBefore != Results.size();
1854 virtual std::optional<FixItList>
1855 getFixits(
const FixitStrategy &S)
const override;
1856 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1858 virtual DeclUseList getClaimedVarUseSites()
const override {
1859 return DeclUseList{PtrLHS, PtrRHS};
1862 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1863 getStrategyImplications()
const override {
1874class CArrayToPtrAssignmentGadget :
public FixableGadget {
1876 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1877 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1878 const DeclRefExpr *PtrLHS;
1879 const DeclRefExpr *PtrRHS;
1883 : FixableGadget(
Kind::CArrayToPtrAssignment),
1884 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1885 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1887 static bool classof(
const Gadget *G) {
1888 return G->getKind() == Kind::CArrayToPtrAssignment;
1891 static bool matches(
const Stmt *S,
1892 llvm::SmallVectorImpl<MatchResult> &Results) {
1893 size_t SizeBefore = Results.size();
1895 const auto *BO = dyn_cast<BinaryOperator>(S);
1896 if (!BO || BO->
getOpcode() != BO_Assign)
1899 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1902 !isSupportedVariable(*RHSRef)) {
1905 const auto *LHS = BO->
getLHS();
1906 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1908 !isSupportedVariable(*LHSRef)) {
1912 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1913 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1914 Results.emplace_back(std::move(R));
1916 return SizeBefore != Results.size();
1919 virtual std::optional<FixItList>
1920 getFixits(
const FixitStrategy &S)
const override;
1921 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1923 virtual DeclUseList getClaimedVarUseSites()
const override {
1924 return DeclUseList{PtrLHS, PtrRHS};
1927 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1928 getStrategyImplications()
const override {
1935class UnsafeBufferUsageAttrGadget :
public WarningGadget {
1936 constexpr static const char *
const OpTag =
"attr_expr";
1941 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
1942 Op(
Result.getNodeAs<Expr>(OpTag)) {}
1944 static bool classof(
const Gadget *G) {
1945 return G->getKind() == Kind::UnsafeBufferUsageAttr;
1948 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1950 if (
auto *CE = dyn_cast<CallExpr>(S)) {
1951 if (CE->getDirectCallee() &&
1952 CE->getDirectCallee()->hasAttr<UnsafeBufferUsageAttr>()) {
1953 Result.addNode(OpTag, DynTypedNode::create(*CE));
1957 if (
auto *ME = dyn_cast<MemberExpr>(S)) {
1960 if (ME->getMemberDecl()->hasAttr<UnsafeBufferUsageAttr>()) {
1961 Result.addNode(OpTag, DynTypedNode::create(*ME));
1968 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1969 bool IsRelatedToDecl,
1970 ASTContext &Ctx)
const override {
1973 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1975 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1977 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1983class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
1984 constexpr static const char *
const OpTag =
"cxx_construct_expr";
1985 const CXXConstructExpr *Op;
1989 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
1990 Op(
Result.getNodeAs<CXXConstructExpr>(OpTag)) {}
1992 static bool classof(
const Gadget *G) {
1993 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
1997 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1998 if (!CE || !CE->getConstructor()->hasAttr<UnsafeBufferUsageAttr>())
2002 if (SpanTwoParamConstructorGadget::matches(CE, Ctx, Tmp))
2004 Result.addNode(OpTag, DynTypedNode::create(*CE));
2008 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2009 bool IsRelatedToDecl,
2010 ASTContext &Ctx)
const override {
2013 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2015 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2017 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2024class DataInvocationGadget :
public WarningGadget {
2025 constexpr static const char *
const OpTag =
"data_invocation_expr";
2026 const ExplicitCastExpr *Op;
2030 : WarningGadget(
Kind::DataInvocation),
2031 Op(
Result.getNodeAs<ExplicitCastExpr>(OpTag)) {}
2033 static bool classof(
const Gadget *G) {
2034 return G->getKind() == Kind::DataInvocation;
2037 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2039 auto *CE = dyn_cast<ExplicitCastExpr>(S);
2042 for (
auto *Child : CE->children()) {
2043 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Child);
2044 MCE && isDataFunction(MCE)) {
2045 Result.addNode(OpTag, DynTypedNode::create(*CE));
2048 if (
auto *
Paren = dyn_cast<ParenExpr>(Child)) {
2049 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(
Paren->getSubExpr());
2050 MCE && isDataFunction(MCE)) {
2051 Result.addNode(OpTag, DynTypedNode::create(*CE));
2059 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2060 bool IsRelatedToDecl,
2061 ASTContext &Ctx)
const override {
2064 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2066 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2069 static bool isDataFunction(
const CXXMemberCallExpr *call) {
2076 if (method->getNameAsString() ==
"data" &&
2077 method->getParent()->isInStdNamespace() &&
2078 llvm::is_contained({SIZED_CONTAINER_OR_VIEW_LIST},
2079 method->getParent()->getName()))
2084 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2087class UnsafeLibcFunctionCallGadget :
public WarningGadget {
2088 const CallExpr *
const Call;
2089 const Expr *UnsafeArg =
nullptr;
2090 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
2092 constexpr static const char *
const UnsafeSprintfTag =
2093 "UnsafeLibcFunctionCall_sprintf";
2094 constexpr static const char *
const UnsafeSizedByTag =
2095 "UnsafeLibcFunctionCall_sized_by";
2096 constexpr static const char *
const UnsafeStringTag =
2097 "UnsafeLibcFunctionCall_string";
2098 constexpr static const char *
const UnsafeVaListTag =
2099 "UnsafeLibcFunctionCall_va_list";
2112 } WarnedFunKind = OTHERS;
2115 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2116 Call(
Result.getNodeAs<CallExpr>(Tag)) {
2117 if (
Result.getNodeAs<Decl>(UnsafeSprintfTag))
2118 WarnedFunKind = SPRINTF;
2119 else if (
auto *E =
Result.getNodeAs<Expr>(UnsafeStringTag)) {
2120 WarnedFunKind = STRING;
2122 }
else if (
Result.getNodeAs<CallExpr>(UnsafeSizedByTag)) {
2123 WarnedFunKind = SIZED_BY;
2124 UnsafeArg = Call->getArg(0);
2125 }
else if (
Result.getNodeAs<Decl>(UnsafeVaListTag))
2126 WarnedFunKind = VA_LIST;
2129 static bool matches(
const Stmt *S, ASTContext &Ctx,
2130 const UnsafeBufferUsageHandler *Handler,
2134 auto *CE = dyn_cast<CallExpr>(S);
2135 if (!CE || !CE->getDirectCallee())
2137 const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
2141 bool IsGlobalAndNotInAnyNamespace =
2142 FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
2146 if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
2152 auto isSingleStringLiteralArg =
false;
2153 if (CE->getNumArgs() == 1) {
2154 isSingleStringLiteralArg =
2157 if (!isSingleStringLiteralArg) {
2160 Result.addNode(Tag, DynTypedNode::create(*CE));
2164 Result.addNode(Tag, DynTypedNode::create(*CE));
2165 Result.addNode(UnsafeVaListTag, DynTypedNode::create(*FD));
2169 Result.addNode(Tag, DynTypedNode::create(*CE));
2170 Result.addNode(UnsafeSprintfTag, DynTypedNode::create(*FD));
2176 Result.addNode(Tag, DynTypedNode::create(*CE));
2177 Result.addNode(UnsafeSizedByTag, DynTypedNode::create(*CE));
2182 Result.addNode(Tag, DynTypedNode::create(*CE));
2189 const Stmt *getBaseStmt()
const {
return Call; }
2191 SourceLocation getSourceLoc()
const override {
return Call->getBeginLoc(); }
2193 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2194 bool IsRelatedToDecl,
2195 ASTContext &Ctx)
const override {
2199 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2201 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2204class UnsafeFormatAttributedFunctionCallGadget :
public WarningGadget {
2205 const CallExpr *
const Call;
2206 const Expr *UnsafeArg =
nullptr;
2207 constexpr static const char *
const Tag =
"UnsafeFormatAttributedFunctionCall";
2208 constexpr static const char *
const UnsafeStringTag =
2209 "UnsafeFormatAttributedFunctionCall_string";
2213 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2214 Call(
Result.getNodeAs<CallExpr>(Tag)),
2215 UnsafeArg(
Result.getNodeAs<Expr>(UnsafeStringTag)) {}
2217 static bool matches(
const Stmt *S, ASTContext &Ctx,
2218 const UnsafeBufferUsageHandler *Handler,
2222 auto *CE = dyn_cast<CallExpr>(S);
2223 if (!CE || !CE->getDirectCallee())
2225 const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
2229 const FormatAttr *Attr =
nullptr;
2230 bool IsPrintf =
false;
2231 bool AnyAttr = llvm::any_of(
2232 FD->specific_attrs<FormatAttr>(),
2233 [&Attr, &IsPrintf](
const FormatAttr *FA) ->
bool {
2234 if (const auto *II = FA->getType()) {
2235 if (II->getName() ==
"printf" || II->getName() ==
"scanf") {
2237 IsPrintf = II->getName() ==
"printf";
2243 const Expr *UnsafeArg;
2249 unsigned FmtIdx = Attr->getFormatIdx() - 1;
2250 std::optional<unsigned> FmtArgIdx = Attr->getFirstArg() - 1;
2260 }
else if (CE->getStmtClass() != Stmt::CallExprClass &&
2263 if (*FmtArgIdx >= CE->getNumArgs())
2270 FmtArgIdx = std::nullopt;
2272 if (AnyAttr && !IsPrintf && FmtArgIdx) {
2274 Result.addNode(Tag, DynTypedNode::create(*CE));
2279 Ctx, CE, UnsafeArg, FmtIdx, FmtArgIdx)) {
2280 Result.addNode(Tag, DynTypedNode::create(*CE));
2281 Result.addNode(UnsafeStringTag, DynTypedNode::create(*UnsafeArg));
2287 const Stmt *getBaseStmt()
const {
return Call; }
2292 bool IsRelatedToDecl,
2296 Call, UnsafeLibcFunctionCallGadget::UnsafeKind::STRING, Ctx,
2300 Call, UnsafeLibcFunctionCallGadget::UnsafeKind::OTHERS, Ctx);
2303 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2311class ULCArraySubscriptGadget :
public FixableGadget {
2313 static constexpr const char *
const ULCArraySubscriptTag =
2314 "ArraySubscriptUnderULC";
2315 const ArraySubscriptExpr *Node;
2319 : FixableGadget(
Kind::ULCArraySubscript),
2320 Node(
Result.getNodeAs<ArraySubscriptExpr>(ULCArraySubscriptTag)) {
2321 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2324 static bool classof(
const Gadget *G) {
2325 return G->getKind() == Kind::ULCArraySubscript;
2328 static bool matches(
const Stmt *S,
2329 llvm::SmallVectorImpl<MatchResult> &Results) {
2330 size_t SizeBefore = Results.size();
2332 const auto *ASE = dyn_cast<ArraySubscriptExpr>(E);
2338 !isSupportedVariable(*DRE))
2341 R.addNode(ULCArraySubscriptTag, DynTypedNode::create(*ASE));
2342 Results.emplace_back(std::move(R));
2344 return SizeBefore != Results.size();
2347 virtual std::optional<FixItList>
2348 getFixits(
const FixitStrategy &S)
const override;
2349 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2351 virtual DeclUseList getClaimedVarUseSites()
const override {
2352 if (
const auto *DRE =
2353 dyn_cast<DeclRefExpr>(Node->getBase()->IgnoreImpCasts())) {
2363class UPCStandalonePointerGadget :
public FixableGadget {
2365 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
2366 const DeclRefExpr *Node;
2370 : FixableGadget(
Kind::UPCStandalonePointer),
2371 Node(
Result.getNodeAs<DeclRefExpr>(DeclRefExprTag)) {
2372 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2375 static bool classof(
const Gadget *G) {
2376 return G->getKind() == Kind::UPCStandalonePointer;
2379 static bool matches(
const Stmt *S,
2380 llvm::SmallVectorImpl<MatchResult> &Results) {
2381 size_t SizeBefore = Results.size();
2383 auto *E = dyn_cast<Expr>(S);
2388 !isSupportedVariable(*DRE))
2391 R.addNode(DeclRefExprTag, DynTypedNode::create(*DRE));
2392 Results.emplace_back(std::move(R));
2394 return SizeBefore != Results.size();
2397 virtual std::optional<FixItList>
2398 getFixits(
const FixitStrategy &S)
const override;
2399 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2401 virtual DeclUseList getClaimedVarUseSites()
const override {
return {Node}; }
2404class PointerDereferenceGadget :
public FixableGadget {
2405 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2406 static constexpr const char *
const OperatorTag =
"op";
2408 const DeclRefExpr *BaseDeclRefExpr =
nullptr;
2409 const UnaryOperator *Op =
nullptr;
2413 : FixableGadget(
Kind::PointerDereference),
2414 BaseDeclRefExpr(
Result.getNodeAs<DeclRefExpr>(BaseDeclRefExprTag)),
2415 Op(
Result.getNodeAs<UnaryOperator>(OperatorTag)) {}
2417 static bool classof(
const Gadget *G) {
2418 return G->getKind() == Kind::PointerDereference;
2421 static bool matches(
const Stmt *S,
2422 llvm::SmallVectorImpl<MatchResult> &Results) {
2423 size_t SizeBefore = Results.size();
2425 const auto *UO = dyn_cast<UnaryOperator>(S);
2428 const auto *CE = dyn_cast<Expr>(UO->
getSubExpr());
2431 CE = CE->IgnoreParenImpCasts();
2432 const auto *DRE = dyn_cast<DeclRefExpr>(CE);
2433 if (!DRE || !isSupportedVariable(*DRE))
2436 R.addNode(BaseDeclRefExprTag, DynTypedNode::create(*DRE));
2437 R.addNode(OperatorTag, DynTypedNode::create(*UO));
2438 Results.emplace_back(std::move(R));
2440 return SizeBefore != Results.size();
2443 DeclUseList getClaimedVarUseSites()
const override {
2444 return {BaseDeclRefExpr};
2447 virtual std::optional<FixItList>
2448 getFixits(
const FixitStrategy &S)
const override;
2449 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2455class UPCAddressofArraySubscriptGadget :
public FixableGadget {
2457 static constexpr const char *
const UPCAddressofArraySubscriptTag =
2458 "AddressofArraySubscriptUnderUPC";
2459 const UnaryOperator *Node;
2463 : FixableGadget(
Kind::ULCArraySubscript),
2464 Node(
Result.getNodeAs<UnaryOperator>(UPCAddressofArraySubscriptTag)) {
2465 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2468 static bool classof(
const Gadget *G) {
2469 return G->getKind() == Kind::UPCAddressofArraySubscript;
2472 static bool matches(
const Stmt *S,
2473 llvm::SmallVectorImpl<MatchResult> &Results) {
2474 size_t SizeBefore = Results.size();
2476 auto *E = dyn_cast<Expr>(S);
2480 if (!UO || UO->
getOpcode() != UO_AddrOf)
2482 const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->
getSubExpr());
2487 if (!DRE || !isSupportedVariable(*DRE))
2490 R.addNode(UPCAddressofArraySubscriptTag, DynTypedNode::create(*UO));
2491 Results.emplace_back(std::move(R));
2493 return SizeBefore != Results.size();
2496 virtual std::optional<FixItList>
2497 getFixits(
const FixitStrategy &)
const override;
2498 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2500 virtual DeclUseList getClaimedVarUseSites()
const override {
2513class DeclUseTracker {
2514 using UseSetTy = llvm::SmallPtrSet<const DeclRefExpr *, 16>;
2515 using DefMapTy = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
2518 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
2522 DeclUseTracker() =
default;
2523 DeclUseTracker(
const DeclUseTracker &) =
delete;
2524 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
2525 DeclUseTracker(DeclUseTracker &&) =
default;
2526 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
2529 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
2532 void claimUse(
const DeclRefExpr *DRE) {
2533 assert(Uses->count(DRE) &&
2534 "DRE not found or claimed by multiple matchers!");
2539 bool hasUnclaimedUses(
const VarDecl *VD)
const {
2541 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
2546 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
2548 for (
auto use : *Uses) {
2550 ReturnSet.insert(use);
2556 void discoverDecl(
const DeclStmt *DS) {
2557 for (
const Decl *D : DS->
decls()) {
2558 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
2569 const DeclStmt *lookupDecl(
const VarDecl *VD)
const {
2570 return Defs.lookup(VD);
2579 static constexpr const char *
const UPCPreIncrementTag =
2580 "PointerPreIncrementUnderUPC";
2585 : FixableGadget(Kind::UPCPreIncrement),
2587 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2591 return G->getKind() == Kind::UPCPreIncrement;
2600 size_t SizeBefore = Results.size();
2602 auto *E = dyn_cast<Expr>(S);
2606 if (!UO || UO->
getOpcode() != UO_PreInc)
2608 const auto *DRE = dyn_cast<DeclRefExpr>(UO->
getSubExpr());
2609 if (!DRE || !isSupportedVariable(*DRE))
2613 Results.emplace_back(std::move(R));
2615 return SizeBefore != Results.size();
2618 virtual std::optional<FixItList>
2623 return {dyn_cast<DeclRefExpr>(Node->getSubExpr())};
2631 static constexpr const char *
const UUCAddAssignTag =
2632 "PointerAddAssignUnderUUC";
2633 static constexpr const char *
const OffsetTag =
"Offset";
2636 const Expr *Offset =
nullptr;
2640 : FixableGadget(Kind::UUCAddAssign),
2643 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2647 return G->getKind() == Kind::UUCAddAssign;
2652 size_t SizeBefore = Results.size();
2654 const auto *E = dyn_cast<Expr>(S);
2658 if (!BO || BO->
getOpcode() != BO_AddAssign)
2660 const auto *DRE = dyn_cast<DeclRefExpr>(BO->
getLHS());
2666 Results.emplace_back(std::move(R));
2668 return SizeBefore != Results.size();
2671 virtual std::optional<FixItList>
2676 return {dyn_cast<DeclRefExpr>(Node->getLHS())};
2683 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2684 static constexpr const char *
const DerefOpTag =
"DerefOp";
2685 static constexpr const char *
const AddOpTag =
"AddOp";
2686 static constexpr const char *
const OffsetTag =
"Offset";
2695 : FixableGadget(Kind::DerefSimplePtrArithFixable),
2703 auto IsPtr = [](
const Expr *E, MatchResult &R) {
2707 if (!DRE || !isSupportedVariable(*DRE))
2712 const auto IsPlusOverPtrAndInteger = [&IsPtr](
const Expr *E,
2714 const auto *BO = dyn_cast<BinaryOperator>(E);
2718 const auto *LHS = BO->
getLHS();
2719 const auto *RHS = BO->
getRHS();
2732 size_t SizeBefore = Results.size();
2733 const auto InnerMatcher = [&IsPlusOverPtrAndInteger,
2734 &Results](
const Expr *E) {
2735 const auto *UO = dyn_cast<UnaryOperator>(E);
2741 if (IsPlusOverPtrAndInteger(Operand, R)) {
2743 Results.emplace_back(std::move(R));
2747 return SizeBefore != Results.size();
2750 virtual std::optional<FixItList>
2753 return DerefOp->getBeginLoc();
2757 return {BaseDeclRefExpr};
2765 : WarningGadgets(WarningGadgets) {}
2774#define WARNING_GADGET(name) \
2775 if (name##Gadget::matches(S, Ctx, Result) && \
2776 notInSafeBufferOptOut(*S, &Handler)) { \
2777 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2780#define WARNING_OPTIONAL_GADGET(name) \
2781 if (name##Gadget::matches(S, Ctx, &Handler, Result) && \
2782 notInSafeBufferOptOut(*S, &Handler)) { \
2783 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2786#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2791 WarningGadgetList &WarningGadgets;
2798 DeclUseTracker &Tracker)
2799 : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
2803 bool matchFound =
false;
2810#define FIXABLE_GADGET(name) \
2811 if (name##Gadget::matches(S, Results)) { \
2812 for (const auto &R : Results) { \
2813 FixableGadgets.push_back(std::make_unique<name##Gadget>(R)); \
2814 matchFound = true; \
2818#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2821 if (
auto *DRE = findDeclRefExpr(S); DRE) {
2822 Tracker.discoverUse(DRE);
2828 if (
auto *DS = findDeclStmt(S); DS) {
2829 Tracker.discoverDecl(DS);
2837 const auto *DRE = dyn_cast<DeclRefExpr>(S);
2845 const DeclStmt *findDeclStmt(
const Stmt *S) {
2846 const auto *DS = dyn_cast<DeclStmt>(S);
2851 FixableGadgetList &FixableGadgets;
2852 DeclUseTracker &Tracker;
2858 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2859 WarningGadgetList &WarningGadgets,
2860 DeclUseTracker &Tracker) {
2863 if (EmitSuggestions) {
2872 return N1->getBeginLoc().getRawEncoding() <
2873 N2->getBeginLoc().getRawEncoding();
2883 const Expr *UnsafeArg =
nullptr)
override {}
2891 bool IsRelatedToDecl,
2912 FixableGadgetList FixableGadgets;
2913 WarningGadgetList WarningGadgets;
2914 DeclUseTracker Tracker;
2915 MockReporter IgnoreHandler;
2918 FixableGadgets, WarningGadgets, Tracker);
2920 std::set<const Expr *>
Result;
2921 for (
auto &G : WarningGadgets) {
2922 for (
const Expr *E : G->getUnsafePtrs()) {
2931 std::map<const VarDecl *, std::set<const WarningGadget *>,
2945 for (
auto &G : AllUnsafeOperations) {
2946 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
2948 bool AssociatedWithVarDecl =
false;
2949 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
2950 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2951 result.
byVar[VD].insert(G.get());
2952 AssociatedWithVarDecl =
true;
2956 if (!AssociatedWithVarDecl) {
2957 result.
noVar.push_back(G.get());
2965 std::map<const VarDecl *, std::set<const FixableGadget *>,
2975 for (
auto &F : AllFixableOperations) {
2976 DeclUseList DREs = F->getClaimedVarUseSites();
2979 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2980 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
2984 return FixablesForUnsafeVars;
2991 std::vector<const FixItHint *>
All;
2995 std::sort(
All.begin(),
All.end(),
2997 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
2998 H2->RemoveRange.getBegin());
3006 Hint->RemoveRange.getBegin())) {
3018std::optional<FixItList>
3019PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
3022 switch (S.
lookup(LeftVD)) {
3026 return std::nullopt;
3028 return std::nullopt;
3031 return std::nullopt;
3033 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3035 return std::nullopt;
3039static inline std::optional<FixItList>
createDataFixit(
const ASTContext &Ctx,
3040 const DeclRefExpr *DRE);
3042std::optional<FixItList>
3043CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
3062 if (S.
lookup(LeftVD) == FixitStrategy::Kind::Span) {
3063 if (S.
lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
3066 }
else if (S.
lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
3067 if (S.
lookup(RightVD) == FixitStrategy::Kind::Array) {
3071 return std::nullopt;
3074std::optional<FixItList>
3075PointerInitGadget::getFixits(
const FixitStrategy &S)
const {
3076 const auto *LeftVD = PtrInitLHS;
3078 switch (S.
lookup(LeftVD)) {
3079 case FixitStrategy::Kind::Span:
3080 if (S.
lookup(RightVD) == FixitStrategy::Kind::Span)
3082 return std::nullopt;
3083 case FixitStrategy::Kind::Wontfix:
3084 return std::nullopt;
3085 case FixitStrategy::Kind::Iterator:
3086 case FixitStrategy::Kind::Array:
3087 return std::nullopt;
3088 case FixitStrategy::Kind::Vector:
3089 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3091 return std::nullopt;
3097 if (ConstVal->isNegative())
3104std::optional<FixItList>
3105ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
3106 if (
const auto *DRE =
3108 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3110 case FixitStrategy::Kind::Span: {
3114 const ASTContext &Ctx =
3117 return std::nullopt;
3121 case FixitStrategy::Kind::Array:
3123 case FixitStrategy::Kind::Wontfix:
3124 case FixitStrategy::Kind::Iterator:
3125 case FixitStrategy::Kind::Vector:
3126 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3129 return std::nullopt;
3132static std::optional<FixItList>
3135std::optional<FixItList>
3136UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
3137 auto DREs = getClaimedVarUseSites();
3141 case FixitStrategy::Kind::Span:
3143 case FixitStrategy::Kind::Wontfix:
3144 case FixitStrategy::Kind::Iterator:
3145 case FixitStrategy::Kind::Array:
3146 return std::nullopt;
3147 case FixitStrategy::Kind::Vector:
3148 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3150 return std::nullopt;
3155 static const char *
const EOL =
"\n";
3162 std::string
s = std::string(
"<# ");
3163 s += HintTextToUser;
3169template <
typename NodeTy>
3170static std::optional<SourceLocation>
3173 if (
unsigned TkLen =
3180 return std::nullopt;
3193 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
3194 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
3195 VD->getBeginLoc())) &&
3196 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
3197 At->getRange().getBegin()));
3201 AttrRangeOverlapping;
3243 std::optional<Qualifiers> Quals = std::nullopt) {
3244 const char *
const SpanOpen =
"std::span<";
3247 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
3248 return SpanOpen + EltTyText.str() +
'>';
3251std::optional<FixItList>
3253 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->getDecl());
3258 if (
auto ConstVal = Offset->getIntegerConstantExpr(Ctx))
3259 if (ConstVal->isNegative())
3260 return std::nullopt;
3281 const Expr *LHS = AddOp->getLHS(), *RHS = AddOp->getRHS();
3288 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
3290 return std::nullopt;
3295 std::optional<SourceLocation> AddOpLocation =
3297 std::optional<SourceLocation> DerefOpLocation =
3300 if (!AddOpLocation || !DerefOpLocation)
3301 return std::nullopt;
3311 return std::nullopt;
3314std::optional<FixItList>
3315PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
3326 if (
auto LocPastOperand =
3333 case FixitStrategy::Kind::Iterator:
3334 case FixitStrategy::Kind::Array:
3335 return std::nullopt;
3336 case FixitStrategy::Kind::Vector:
3337 llvm_unreachable(
"FixitStrategy not implemented yet!");
3338 case FixitStrategy::Kind::Wontfix:
3339 llvm_unreachable(
"Invalid strategy!");
3342 return std::nullopt;
3349 std::optional<SourceLocation> EndOfOperand =
3355 return std::nullopt;
3360std::optional<FixItList>
3361UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
3364 case FixitStrategy::Kind::Array:
3365 case FixitStrategy::Kind::Span: {
3370 case FixitStrategy::Kind::Wontfix:
3371 case FixitStrategy::Kind::Iterator:
3372 return std::nullopt;
3373 case FixitStrategy::Kind::Vector:
3374 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3377 return std::nullopt;
3382static std::optional<FixItList>
3389 const Expr *Idx = ArraySub->getIdx();
3392 std::stringstream SS;
3393 bool IdxIsLitZero =
false;
3396 if ((*ICE).isZero())
3397 IdxIsLitZero =
true;
3398 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
3400 return std::nullopt;
3404 SS << (*DreString).str() <<
".data()";
3406 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
3408 return std::nullopt;
3410 SS <<
"&" << (*DreString).str() <<
".data()"
3411 <<
"[" << (*IndexString).str() <<
"]";
3417std::optional<FixItList>
3421 if (DREs.size() != 1)
3422 return std::nullopt;
3424 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3428 const Stmt *AddAssignNode = Node;
3429 StringRef varName = VD->
getName();
3433 return std::nullopt;
3437 (Offset->IgnoreParens()->getBeginLoc() == Offset->getBeginLoc());
3438 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
3442 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
3444 if (!AddAssignLocation)
3445 return std::nullopt;
3452 Offset->getEndLoc().getLocWithOffset(1),
")"));
3456 return std::nullopt;
3459std::optional<FixItList>
3463 if (DREs.size() != 1)
3464 return std::nullopt;
3466 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3469 std::stringstream SS;
3470 StringRef varName = VD->
getName();
3474 SS <<
"(" << varName.data() <<
" = " << varName.data()
3475 <<
".subspan(1)).data()";
3476 std::optional<SourceLocation> PreIncLocation =
3478 if (!PreIncLocation)
3479 return std::nullopt;
3482 SourceRange(Node->getBeginLoc(), *PreIncLocation), SS.str()));
3486 return std::nullopt;
3504static std::optional<FixItList>
3506 const StringRef UserFillPlaceHolder) {
3514 if (
Init->isNullPointerConstant(
3519 NPC_ValueDependentIsNotNull)) {
3520 std::optional<SourceLocation> InitLocation =
3523 return std::nullopt;
3531 std::string ExtentText = UserFillPlaceHolder.data();
3532 StringRef One =
"1";
3537 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
3542 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
3543 if (!Ext->HasSideEffects(Ctx)) {
3544 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
3546 return std::nullopt;
3547 ExtentText = *ExtentString;
3549 }
else if (!CxxNew->isArray())
3561 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
3562 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
3563 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
3570 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
3573 return std::nullopt;
3575 StrBuffer.append(
", ");
3576 StrBuffer.append(ExtentText);
3577 StrBuffer.append(
"}");
3583#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
3584 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
3585 "failed to produce fixit for declaration '" + \
3586 (D)->getNameAsString() + "'" + (Msg))
3588#define DEBUG_NOTE_DECL_FAIL(D, Msg)
3594static std::optional<std::string>
3598 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3603 return std::nullopt;
3605 std::string SpanTyText =
"std::span<";
3607 SpanTyText.append(*PteTyText);
3609 if (PteTyQualifiers) {
3610 SpanTyText.append(
" ");
3611 SpanTyText.append(PteTyQualifiers->getAsString());
3613 SpanTyText.append(
">");
3632 const StringRef UserFillPlaceHolder,
3646 std::stringstream SS;
3651 std::optional<FixItList> InitFixIts =
3655 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
3656 std::make_move_iterator(InitFixIts->end()));
3663 if (!EndLocForReplacement.
isValid()) {
3713static std::optional<FixItList>
3719 return std::nullopt;
3724 std::vector<std::string> NewTysTexts(NumParms);
3725 std::vector<bool> ParmsMask(NumParms,
false);
3726 bool AtLeastOneParmToFix =
false;
3728 for (
unsigned i = 0; i < NumParms; i++) {
3735 return std::nullopt;
3737 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3738 std::optional<std::string> PteTyText =
3743 return std::nullopt;
3747 ParmsMask[i] =
true;
3748 AtLeastOneParmToFix =
true;
3750 if (!AtLeastOneParmToFix)
3757 const auto NewOverloadSignatureCreator =
3758 [&
SM, &LangOpts, &NewTysTexts,
3759 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3760 std::stringstream SS;
3768 SS << Prefix->str();
3770 return std::nullopt;
3774 for (
unsigned i = 0; i < NumParms; i++) {
3782 SS << NewTysTexts[i];
3785 SS <<
' ' << II->getName().str();
3786 }
else if (
auto ParmTypeText =
3790 SS << ParmTypeText->str();
3792 return std::nullopt;
3793 if (i != NumParms - 1)
3802 const auto OldOverloadDefCreator =
3803 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3804 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3805 std::stringstream SS;
3813 << FDPrefix->str() <<
"{";
3815 return std::nullopt;
3818 SS <<
"return " << FunQualName->str() <<
"(";
3820 return std::nullopt;
3824 for (
unsigned i = 0; i < NumParms; i++) {
3833 return std::nullopt;
3840 if (i != NumParms - 1)
3851 std::optional<SourceLocation> Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3855 if (FReDecl->isThisDeclarationADefinition()) {
3856 assert(FReDecl == FD &&
"inconsistent function definition");
3859 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3865 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3868 FReDecl->getBeginLoc(),
" ")));
3871 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3893 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3909 std::stringstream SS;
3912 if (PteTyQualifiers)
3921 SS <<
' ' << PVDNameText->str();
3927 const DeclUseTracker &Tracker,
3930 const DeclStmt *DS = Tracker.lookupDecl(VD);
3933 " : variables declared this way not implemented yet");
3957 const QualType &ArrayEltT = CAT->getElementType();
3958 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
3967 auto MaybeElemTypeTxt =
3970 if (!MaybeElemTypeTxt)
3972 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
3977 while (NextTok && !NextTok->is(tok::l_square) &&
3990 if (!MaybeArraySizeTxt)
3992 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
3993 if (ArraySizeTxt.empty()) {
4004 std::optional<StringRef> IdentText =
4013 llvm::raw_svector_ostream OS(Replacement);
4014 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
4015 << IdentText->str();
4025 const DeclUseTracker &Tracker,
4028 const DeclStmt *DS = Tracker.lookupDecl(VD);
4029 assert(DS &&
"Fixing non-local variables not implemented yet!");
4048 const DeclUseTracker &Tracker,
ASTContext &Ctx,
4050 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
4051 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
4052 if (!FD || FD != D) {
4063 if (FD->isMain() || FD->isConstexpr() ||
4070 FD->isOverloadedOperator()) {
4079 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
4097 llvm_unreachable(
"FixitStrategy not implemented yet!");
4099 llvm_unreachable(
"Invalid strategy!");
4101 llvm_unreachable(
"Unknown strategy!");
4109 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
4111 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
4128 std::map<const VarDecl *, FixItList> &FixItsForVariable,
4133 for (
const auto &[VD, Ignore] : FixItsForVariable) {
4135 if (llvm::any_of(Grp,
4136 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
4137 return !FixItsForVariable.count(GrpMember);
4142 ToErase.push_back(
Member);
4145 for (
auto *VarToErase : ToErase)
4146 FixItsForVariable.erase(VarToErase);
4157 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
4161 FixItList FixItsSharedByParms{};
4163 std::optional<FixItList> OverloadFixes =
4166 if (OverloadFixes) {
4167 FixItsSharedByParms.append(*OverloadFixes);
4173 FixItsForVariable.erase(
Member);
4175 return FixItsSharedByParms;
4179static std::map<const VarDecl *, FixItList>
4188 std::map<const VarDecl *, FixItList> FixItsForVariable;
4193 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
4194 FixItsForVariable[VD] =
4198 if (FixItsForVariable[VD].empty()) {
4199 FixItsForVariable.erase(VD);
4202 for (
const auto &F : Fixables) {
4203 std::optional<FixItList> Fixits = F->getFixits(S);
4206 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
4207 Fixits->begin(), Fixits->end());
4212 VD, F->getSourceLoc(),
4213 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
4216 FixItsForVariable.erase(VD);
4235 FixItList FixItsSharedByParms{};
4237 if (
auto *FD = dyn_cast<FunctionDecl>(D))
4239 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
4243 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
4246 for (
auto &[Var, Ignore] : FixItsForVariable) {
4247 bool AnyParm =
false;
4248 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
4250 for (
const VarDecl *GrpMate : VarGroupForVD) {
4253 if (FixItsForVariable.count(GrpMate))
4254 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
4258 assert(!FixItsSharedByParms.empty() &&
4259 "Should not try to fix a parameter that does not belong to a "
4261 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
4268 for (
auto Iter = FinalFixItsForVariable.begin();
4269 Iter != FinalFixItsForVariable.end();)
4272 Iter = FinalFixItsForVariable.erase(Iter);
4275 return FinalFixItsForVariable;
4278template <
typename VarDeclIterTy>
4282 for (
const VarDecl *VD : UnsafeVars) {
4293 const std::vector<VarGrpTy> &Groups;
4294 const std::map<const VarDecl *, unsigned> &VarGrpMap;
4295 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
4299 const std::vector<VarGrpTy> &Groups,
4300 const std::map<const VarDecl *, unsigned> &VarGrpMap,
4301 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
4302 : Groups(Groups), VarGrpMap(VarGrpMap),
4303 GrpsUnionForParms(GrpsUnionForParms) {}
4306 if (GrpsUnionForParms.contains(Var)) {
4309 return GrpsUnionForParms.getArrayRef();
4314 auto It = VarGrpMap.find(Var);
4316 if (It == VarGrpMap.end())
4318 return Groups[It->second];
4322 return GrpsUnionForParms.getArrayRef();
4327 WarningGadgetList WarningGadgets,
4328 DeclUseTracker Tracker,
4330 bool EmitSuggestions) {
4331 if (!EmitSuggestions) {
4335 for (
const auto &G : WarningGadgets) {
4336 G->handleUnsafeOperation(Handler,
false,
4342 assert(FixableGadgets.empty() &&
4343 "Fixable gadgets found but suggestions not requested!");
4349 if (!WarningGadgets.empty()) {
4353 for (
const auto &G : FixableGadgets) {
4354 for (
const auto *DRE : G->getClaimedVarUseSites()) {
4355 Tracker.claimUse(DRE);
4371 if (WarningGadgets.empty())
4379 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
4382 for (
auto it = FixablesForAllVars.
byVar.cbegin();
4383 it != FixablesForAllVars.
byVar.cend();) {
4388 (
"failed to produce fixit for '" +
4389 it->first->getNameAsString() +
4390 "' : neither local nor a parameter"));
4392 it = FixablesForAllVars.
byVar.erase(it);
4393 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
4396 (
"failed to produce fixit for '" +
4397 it->first->getNameAsString() +
4398 "' : has a reference type"));
4400 it = FixablesForAllVars.
byVar.erase(it);
4401 }
else if (Tracker.hasUnclaimedUses(it->first)) {
4402 it = FixablesForAllVars.
byVar.erase(it);
4403 }
else if (it->first->isInitCapture()) {
4406 (
"failed to produce fixit for '" +
4407 it->first->getNameAsString() +
4408 "' : init capture"));
4410 it = FixablesForAllVars.
byVar.erase(it);
4417 for (
const auto &it : UnsafeOps.
byVar) {
4418 const VarDecl *
const UnsafeVD = it.first;
4419 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
4420 if (UnclaimedDREs.empty())
4424 std::string UnclaimedUseTrace =
4429 (
"failed to produce fixit for '" + UnfixedVDName +
4430 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
4431 UnclaimedUseTrace));
4438 llvm::DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
4439 DepMapTy DependenciesMap{};
4440 DepMapTy PtrAssignmentGraph{};
4442 for (
const auto &it : FixablesForAllVars.
byVar) {
4443 for (
const FixableGadget *fixable : it.second) {
4444 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
4445 fixable->getStrategyImplications();
4447 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
4448 PtrAssignmentGraph[Impl.first].insert(Impl.second);
4470 std::set<const VarDecl *> VisitedVarsDirected{};
4471 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4472 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
4474 std::queue<const VarDecl *> QueueDirected{};
4475 QueueDirected.push(Var);
4476 while (!QueueDirected.empty()) {
4477 const VarDecl *CurrentVar = QueueDirected.front();
4478 QueueDirected.pop();
4479 VisitedVarsDirected.insert(CurrentVar);
4480 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
4481 for (
const VarDecl *Adj : AdjacentNodes) {
4482 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
4483 QueueDirected.push(Adj);
4485 DependenciesMap[Var].insert(Adj);
4486 DependenciesMap[Adj].insert(Var);
4493 std::vector<VarGrpTy> Groups;
4497 std::map<const VarDecl *, unsigned> VarGrpMap;
4499 llvm::SetVector<const VarDecl *>
4504 std::set<const VarDecl *> VisitedVars{};
4505 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4506 if (VisitedVars.find(Var) == VisitedVars.end()) {
4507 VarGrpTy &VarGroup = Groups.emplace_back();
4508 std::queue<const VarDecl *> Queue{};
4511 while (!Queue.empty()) {
4512 const VarDecl *CurrentVar = Queue.front();
4514 VisitedVars.insert(CurrentVar);
4515 VarGroup.push_back(CurrentVar);
4516 auto AdjacentNodes = DependenciesMap[CurrentVar];
4517 for (
const VarDecl *Adj : AdjacentNodes) {
4518 if (VisitedVars.find(Adj) == VisitedVars.end()) {
4524 bool HasParm =
false;
4525 unsigned GrpIdx = Groups.size() - 1;
4527 for (
const VarDecl *
V : VarGroup) {
4528 VarGrpMap[
V] = GrpIdx;
4533 GrpsUnionForParms.insert_range(VarGroup);
4555 for (
auto I = FixablesForAllVars.
byVar.begin();
4556 I != FixablesForAllVars.
byVar.end();) {
4558 if (!VisitedVars.count((*I).first)) {
4560 I = FixablesForAllVars.
byVar.erase(I);
4568 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
4570 return FixablesForAllVars.
byVar.count(
V);
4577 FixItsForVariableGroup =
4579 Tracker, Handler, VarGrpMgr);
4581 for (
const auto &G : UnsafeOps.
noVar) {
4582 G->handleUnsafeOperation(Handler,
false,
4586 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
4587 auto FixItsIt = FixItsForVariableGroup.find(VD);
4589 FixItsIt != FixItsForVariableGroup.end()
4590 ? std::move(FixItsIt->second)
4593 for (
const auto &G : WarningGadgets) {
4594 G->handleUnsafeOperation(Handler,
true,
4602 bool EmitSuggestions) {
4611 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
4614 if (FD->isConsteval())
4619 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
4620 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
4625 if (FReDecl->isExternC()) {
4628 EmitSuggestions =
false;
4633 Stmts.push_back(FD->getBody());
4635 if (
const auto *ID = dyn_cast<CXXConstructorDecl>(D)) {
4637 Stmts.push_back(CI->getInit());
4641 Stmts.push_back(D->
getBody());
4644 assert(!Stmts.empty());
4646 FixableGadgetList FixableGadgets;
4647 WarningGadgetList WarningGadgets;
4648 DeclUseTracker Tracker;
4649 for (
Stmt *S : Stmts) {
4651 WarningGadgets, Tracker);
4653 applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
4654 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 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 void forEachDescendantEvaluatedStmt(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, FastMatcher &Matcher)
static void findStmtsInUnspecifiedUntypedContext(const Stmt *S, llvm::function_ref< void(const Stmt *)> InnerMatcher)
static std::optional< FixItList > createOverloadsForFixedParams(const FixitStrategy &S, const FunctionDecl *FD, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static void eraseVarsForUnfixableGroupMates(std::map< const VarDecl *, FixItList > &FixItsForVariable, const VariableGroupsManager &VarGrpMgr)
static FixableGadgetSets groupFixablesByVar(FixableGadgetList &&AllFixableOperations)
static bool isParameterOf(const VarDecl *VD, const Decl *D)
#define SIZED_CONTAINER_OR_VIEW_LIST
static std::optional< StringRef > getFunNameText(const FunctionDecl *FD, const SourceManager &SM, const LangOptions &LangOpts)
__device__ __2f16 float __ockl_bool s
virtual std::optional< FixItList > getFixits(const FixitStrategy &s) const final
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
DerefSimplePtrArithFixableGadget(const MatchResult &Result)
SourceLocation getSourceLoc() const override
virtual DeclUseList getClaimedVarUseSites() const final
FixableGadgetMatcher(FixableGadgetList &FixableGadgets, DeclUseTracker &Tracker)
bool matches(const DynTypedNode &DynNode, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler) override
Represents the length modifier in a format string in scanf/printf.
bool TraverseCXXTypeidExpr(CXXTypeidExpr *Node) override
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc Node, bool TraverseQualifier) override
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc Node, bool TraverseQualifier) override
bool TraverseGenericSelectionExpr(GenericSelectionExpr *Node) override
MatchDescendantVisitor(ASTContext &Context, FastMatcher &Matcher, bool FindAll, bool IgnoreUnevaluatedContext, const UnsafeBufferUsageHandler &NewHandler)
bool TraverseDecl(Decl *Node) override
bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) override
bool findMatch(const DynTypedNode &DynNode)
bool TraverseCXXDefaultInitExpr(CXXDefaultInitExpr *Node) override
bool TraverseCXXNoexceptExpr(CXXNoexceptExpr *Node) override
bool TraverseStmt(Stmt *Node) override
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
SourceLocation getSourceLoc() const override
virtual DeclUseList getClaimedVarUseSites() const override
UPCPreIncrementGadget(const MatchResult &Result)
static bool classof(const Gadget *G)
static bool classof(const Gadget *G)
UUCAddAssignGadget(const MatchResult &Result)
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
virtual DeclUseList getClaimedVarUseSites() const override
SourceLocation getSourceLoc() const override
VariableGroupsManagerImpl(const std::vector< VarGrpTy > &Groups, const std::map< const VarDecl *, unsigned > &VarGrpMap, const llvm::SetVector< const VarDecl * > &GrpsUnionForParms)
VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm) const override
Returns the set of variables (including Var) that need to be fixed together in one step.
VarGrpRef getGroupOfParms() const override
Returns the non-empty group of variables that include parameters of the analyzing function,...
bool matches(const DynTypedNode &DynNode, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler) override
WarningGadgetMatcher(WarningGadgetList &WarningGadgets)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
const ConstantArrayType * getAsConstantArrayType(QualType T) const
DynTypedNodeList getParents(const NodeT &Node)
Forwards to get node parents from the ParentMapContext.
QualType getFILEType() const
Retrieve the C FILE type.
const LangOptions & getLangOpts() const
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Attr - This represents one attribute.
A builtin binary operation expression such as "x + y" or "x <= y".
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
Represents a call to a C++ constructor.
Expr * getArg(unsigned Arg)
Return the specified argument.
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
Represents a C++ base or member initializer.
A use of a default initializer in a constructor or in aggregate initialization.
Expr * getExpr()
Get the initialization expression that will be used.
Represents a static or instance method of a struct/union/class.
Represents a C++11 noexcept expression (C++ [expr.unary.noexcept]).
OverloadedOperatorKind getOperator() const
Returns the kind of overloaded operator that this expression refers to.
Represents a C++ struct/union/class.
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
A C++ typeid expression (C++ [expr.typeid]), which gets the type_info that corresponds to the supplie...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
static const char * getCastKindName(CastKind CK)
Represents a character-granular source range.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getEnd() const
bool isOne() const
isOne - Test whether the quantity equals one.
Represents a class template specialization, which refers to a class template with a given set of temp...
const TemplateArgumentList & getTemplateArgs() const
Retrieve the template arguments of the class template specialization.
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
bool isSingleResult() const
DeclContext * getParent()
getParent - Returns the containing DeclContext.
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
A reference to a declared variable, function, enum, etc.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
bool isSingleDecl() const
isSingleDecl - This method returns true if this DeclStmt refers to a single Decl.
const Decl * getSingleDecl() const
Decl - This represents one declaration (or definition), e.g.
bool isInStdNamespace() const
SourceLocation getEndLoc() const LLVM_READONLY
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
DeclContext * getDeclContext()
SourceLocation getBeginLoc() const LLVM_READONLY
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
SourceLocation getTypeSpecEndLoc() const
SourceLocation getBeginLoc() const LLVM_READONLY
NestedNameSpecifierLoc getQualifierLoc() const
Retrieve the nested-name-specifier (with source-location information) that qualifies the name of this...
NestedNameSpecifier getQualifier() const
Retrieve the nested-name-specifier that qualifies the name of this declaration, if it was present in ...
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
const DynTypedNode * begin() const
A dynamically typed AST node container.
const T * get() const
Retrieve the stored node as type T.
static DynTypedNode create(const T &Node)
Creates a DynTypedNode from Node.
virtual bool TraverseDecl(MaybeConst< Decl > *D)
bool ShouldVisitTemplateInstantiations
bool ShouldVisitImplicitCode
virtual bool TraverseStmt(MaybeConst< Stmt > *S)
This represents one expression.
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
bool isValueDependent() const
Determines whether the value of this expression depends on.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
NullPointerConstantValueDependence
Enumeration used to describe how isNullPointerConstant() should cope with value-dependent expressions...
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
static FixItHint CreateRemoval(CharSourceRange RemoveRange)
Create a code modification hint that removes the given source range.
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
Kind lookup(const VarDecl *VD) const
void set(const VarDecl *VD, Kind K)
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
unsigned getBuiltinID(bool ConsiderWrapperFunctions=false) const
Returns a value indicating whether this function corresponds to a builtin function.
param_iterator param_begin()
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
DeclarationNameInfo getNameInfo() const
Represents a C11 generic selection.
Expr * getResultExpr()
Return the result expression of this controlling expression.
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
A simple pair of identifier info and location.
static IntegerLiteral * Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l)
Returns a new integer literal with value 'V' and type 'type'.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static std::optional< Token > findNextToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts, bool IncludeComments=false)
Finds the token that comes right after the given location.
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)
Computes the source location just past the end of the token at this source location.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
SourceLocation getBeginLoc() const
Retrieve the location of the beginning of this nested-name-specifier.
A single parameter index whose accessors require each use to make explicit the parameter index encodi...
bool isValid() const
Is this parameter index valid?
unsigned getASTIndex() const
Get the parameter index as it would normally be encoded at the AST level of representation: zero-orig...
Represents a parameter to a function.
bool hasDefaultArg() const
Determines whether this parameter has a default argument, either parsed or not.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
PointerType - C99 6.7.5.1 - Pointer Declarators.
A (possibly-)qualified type.
bool hasQualifiers() const
Determine whether this type has any qualifiers.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
QualType getCanonicalType() const
bool isConstQualified() const
Determine whether this type is const-qualified.
std::string getAsString() const
Represents a struct/union/class.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
Stmt - This represents one statement.
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const char * getStmtClassName() const
SourceLocation getBeginLoc() const LLVM_READONLY
Exposes information about the current target.
A template argument list.
unsigned size() const
Retrieve the number of template arguments in this template argument list.
Represents a template argument.
QualType getAsType() const
Retrieve the type for a type template argument.
@ Type
The template argument is a type.
ArgKind getKind() const
Return the kind of stored template argument.
The base class of the type hierarchy.
bool isConstantSizeType() const
Return true if this is not a variable sized type, according to the rules of C99 6....
bool isPointerType() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
const T * castAs() const
Member-template castAs<specific type>.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isAnyCharacterType() const
Determine whether this type is any of the built-in character types.
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
bool isAnyPointerType() const
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
static bool isIncrementOp(Opcode Op)
SourceLocation getBeginLoc() const LLVM_READONLY
static bool isDecrementOp(Opcode Op)
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
The interface that lets the caller handle unsafe buffer usage analysis results by overriding this cla...
virtual void handleUnsafeUniquePtrArrayAccess(const DynTypedNode &Node, bool IsRelatedToDecl, ASTContext &Ctx)=0
void addDebugNoteForVar(const VarDecl *VD, SourceLocation Loc, std::string Text)
virtual std::string getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, StringRef WSSuffix="") const =0
virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const =0
virtual bool ignoreUnsafeBufferInContainer(const SourceLocation &Loc) const =0
virtual void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation over raw pointers is found.
virtual void handleUnsafeVariableGroup(const VarDecl *Variable, const VariableGroupsManager &VarGrpMgr, FixItList &&Fixes, const Decl *D, const FixitStrategy &VarTargetTypes)=0
Invoked when a fix is suggested against a variable.
virtual void handleUnsafeOperationInContainer(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation with a std container is found.
virtual bool ignoreUnsafeBufferInStaticSizedArray(const SourceLocation &Loc) const =0
virtual bool ignoreUnsafeBufferInLibcCall(const SourceLocation &Loc) const =0
virtual void handleUnsafeLibcCall(const CallExpr *Call, unsigned PrintfInfo, ASTContext &Ctx, const Expr *UnsafeArg=nullptr)=0
Invoked when a call to an unsafe libc function is found.
Represents a variable declaration or definition.
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
VarDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
bool isInlineSpecified() const
bool hasConstantInitialization() const
Determine whether this variable has constant initialization.
const Expr * getInit() const
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
const Expr * getAnyInitializer() const
Get the initializer for this variable, no matter which declaration it is attached to.
VariableGroupsManager()=default
virtual VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm=nullptr) const =0
Returns the set of variables (including Var) that need to be fixed together in one step.
virtual VarGrpRef getGroupOfParms() const =0
Returns the non-empty group of variables that include parameters of the analyzing function,...
unsigned getArgIndex() const
bool hasDataArgument() const
HowSpecified getHowSpecified() const
unsigned getConstantAmount() const
const OptionalAmount & getPrecision() const
const PrintfConversionSpecifier & getConversionSpecifier() const
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
void matchEachArgumentWithParamType(const CallExpr &Node, llvm::function_ref< void(QualType, const Expr *)> OnParamAndArg)
bool anyConflict(const llvm::SmallVectorImpl< FixItHint > &FixIts, const SourceManager &SM)
bool matches(const til::SExpr *E1, const til::SExpr *E2)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
SourceLocation getVarDeclIdentifierLoc(const DeclaratorDecl *VD)
static bool classof(const OMPClause *T)
std::vector< const VarDecl * > VarGrpTy
std::optional< StringRef > getExprText(const Expr *E, const SourceManager &SM, const LangOptions &LangOpts)
@ Result
The result type of a method or function.
const FunctionProtoType * T
std::optional< std::string > getPointeeTypeText(const DeclaratorDecl *VD, const SourceManager &SM, const LangOptions &LangOpts, std::optional< Qualifiers > *QualifiersToAppend)
std::optional< StringRef > getRangeText(SourceRange SR, const SourceManager &SM, const LangOptions &LangOpts)
std::optional< StringRef > getVarDeclIdentifierText(const DeclaratorDecl *VD, const SourceManager &SM, const LangOptions &LangOpts)
std::optional< SourceLocation > getPastLoc(const NodeTy *Node, const SourceManager &SM, const LangOptions &LangOpts)
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
std::set< const Expr * > findUnsafePointers(const FunctionDecl *FD)
ArrayRef< const VarDecl * > VarGrpRef
static bool hasUnsafePrintfStringArg(const CallExpr &Node, ASTContext &Ctx, MatchResult &Result, llvm::StringRef Tag)
static bool isPredefinedUnsafeLibcFunc(const FunctionDecl &Node)
static bool hasUnsafeSnprintfBuffer(const CallExpr &Node, ASTContext &Ctx)
static bool isUnsafeVaListPrintfFunc(const FunctionDecl &Node)
static bool isUnsafeSprintfFunc(const FunctionDecl &Node)
static bool hasUnsafeFormatOrSArg(ASTContext &Ctx, const CallExpr *Call, const Expr *&UnsafeArg, const unsigned FmtIdx, std::optional< const unsigned > FmtArgIdx=std::nullopt, bool isKprintf=false)
static bool isNormalPrintfFunc(const FunctionDecl &Node)
bool operator()(const NodeTy *N1, const NodeTy *N2) const
std::map< const VarDecl *, std::set< const FixableGadget * >, CompareNode< VarDecl > > byVar
std::map< const VarDecl *, std::set< const WarningGadget * >, CompareNode< VarDecl > > byVar
llvm::SmallVector< const WarningGadget *, 16 > noVar
SourceLocation getBeginLoc() const
getBeginLoc - Retrieve the location of the first token.
SourceLocation getEndLoc() const LLVM_READONLY
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.
const BoundNodes Nodes
Contains the nodes bound on the current match.
StringRef matchLibcName(StringRef Name)
StringRef matchName(StringRef FunName, bool isBuiltin)
StringRef matchLibcNameOrBuiltinChk(StringRef Name)