29#include "llvm/ADT/APInt.h"
30#include "llvm/ADT/APSInt.h"
31#include "llvm/ADT/STLExtras.h"
32#include "llvm/ADT/STLFunctionalExtras.h"
33#include "llvm/ADT/SmallVector.h"
34#include "llvm/ADT/StringRef.h"
51 std::string VisitBinaryOperator(
const BinaryOperator *BO) {
52 return "BinaryOperator(" + BO->
getOpcodeStr().str() +
")";
55 std::string VisitUnaryOperator(
const UnaryOperator *UO) {
59 std::string VisitImplicitCastExpr(
const ImplicitCastExpr *ICE) {
66static std::string getDREAncestorString(
const DeclRefExpr *DRE,
70 StmtDebugPrinter StmtPriner;
73 SS << StmtPriner.Visit(St);
77 if (StParents.
size() > 1)
78 return "unavailable due to multiple parents";
79 if (StParents.
empty())
98 virtual bool matches(
const DynTypedNode &DynNode, ASTContext &Ctx,
99 const UnsafeBufferUsageHandler &Handler) = 0;
100 virtual ~FastMatcher() =
default;
106 template <
typename T>
const T *getNodeAs(StringRef ID)
const {
107 auto It =
Nodes.find(ID);
108 if (It ==
Nodes.end()) {
111 return It->second.get<T>();
114 void addNode(StringRef ID,
const DynTypedNode &Node) {
Nodes[
ID] = Node; }
117 llvm::StringMap<DynTypedNode>
Nodes;
121#define SIZED_CONTAINER_OR_VIEW_LIST \
122 "span", "array", "vector", "basic_string_view", "basic_string", \
133 bool FindAll,
bool IgnoreUnevaluatedContext,
135 : Matcher(&Matcher), FindAll(FindAll), Matches(
false),
136 IgnoreUnevaluatedContext(IgnoreUnevaluatedContext),
137 ActiveASTContext(&Context), Handler(&NewHandler) {
174 if (IgnoreUnevaluatedContext)
176 return DynamicRecursiveASTVisitor::TraverseGenericSelectionExpr(Node);
182 if (IgnoreUnevaluatedContext)
184 return DynamicRecursiveASTVisitor::TraverseUnaryExprOrTypeTraitExpr(Node);
188 bool TraverseQualifier)
override {
190 if (IgnoreUnevaluatedContext)
192 return DynamicRecursiveASTVisitor::TraverseTypeOfExprTypeLoc(
193 Node, TraverseQualifier);
197 bool TraverseQualifier)
override {
199 if (IgnoreUnevaluatedContext)
201 return DynamicRecursiveASTVisitor::TraverseDecltypeTypeLoc(
202 Node, TraverseQualifier);
207 if (IgnoreUnevaluatedContext)
209 return DynamicRecursiveASTVisitor::TraverseCXXNoexceptExpr(Node);
214 if (IgnoreUnevaluatedContext)
216 return DynamicRecursiveASTVisitor::TraverseCXXTypeidExpr(Node);
222 return DynamicRecursiveASTVisitor::TraverseCXXDefaultInitExpr(Node);
238 template <
typename T>
bool match(
const T &Node) {
248 FastMatcher *
const Matcher;
252 bool IgnoreUnevaluatedContext;
253 ASTContext *ActiveASTContext;
254 const UnsafeBufferUsageHandler *Handler;
269 FastMatcher &Matcher) {
277 FastMatcher &Matcher) {
305 const Stmt *S,
const llvm::function_ref<
void(
const Expr *)> OnResult) {
306 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(S);
307 CE && CE->getCastKind() == CastKind::CK_LValueToRValue)
308 OnResult(CE->getSubExpr());
309 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
317 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
326 if (
auto *CE = dyn_cast<CallExpr>(S)) {
327 if (
const auto *FnDecl = CE->getDirectCallee();
328 FnDecl && FnDecl->hasAttr<UnsafeBufferUsageAttr>())
337 if (
auto *CE = dyn_cast<CastExpr>(S)) {
338 if (CE->getCastKind() != CastKind::CK_PointerToIntegral &&
339 CE->getCastKind() != CastKind::CK_PointerToBoolean)
343 InnerMatcher(CE->getSubExpr());
347 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
361 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
367 InnerMatcher(BO->
getLHS());
368 InnerMatcher(BO->
getRHS());
386 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
391 if (
auto *CS = dyn_cast<CompoundStmt>(S)) {
392 for (
auto *Child : CS->body())
395 if (
auto *IfS = dyn_cast<IfStmt>(S)) {
397 InnerMatcher(IfS->getThen());
399 InnerMatcher(IfS->getElse());
450 case Stmt::DeclRefExprClass:
452 case Stmt::BinaryOperatorClass: {
455 BO2->getLHS(), BO2->getOpcode(),
472 if (
const auto *UO = dyn_cast<UnaryOperator>(Ptr)) {
473 if (UO->
getOpcode() != UnaryOperator::Opcode::UO_AddrOf)
479 if (
const auto *CE = dyn_cast<CallExpr>(Ptr)) {
484 return CE->getArg(0)->IgnoreParenImpCasts();
494 const auto *SizeOfExpr =
496 if (!SizeOfExpr || SizeOfExpr->getKind() != UETT_SizeOf)
498 if (SizeOfExpr->isArgumentType())
500 return SizeOfExpr->getArgumentExpr()->IgnoreParenImpCasts();
521 dyn_cast<CXXMemberCallExpr>(Size->IgnoreParenImpCasts())) {
522 auto *DREOfPtr = dyn_cast<DeclRefExpr>(
523 MCEPtr->getImplicitObjectArgument()->IgnoreParenImpCasts());
524 auto *DREOfSize = dyn_cast<DeclRefExpr>(
525 MCESize->getImplicitObjectArgument()->IgnoreParenImpCasts());
527 if (!DREOfPtr || !DREOfSize)
531 if (DREOfPtr->getDecl() != DREOfSize->getDecl())
533 if (MCEPtr->getMethodDecl()->getName() !=
"data")
536 if (!MCEPtr->getRecordDecl()->isInStdNamespace())
539 auto *ObjII = MCEPtr->getRecordDecl()->getIdentifier();
546 if (!((AcceptSizeBytes &&
547 MCESize->getMethodDecl()->getName() ==
"size_bytes") ||
552 MCESize->getMethodDecl()->getName() ==
"size"))
562 if (Size->EvaluateAsInt(ER, Ctx)) {
568 return llvm::APSInt::compareValues(
569 SizeInt, llvm::APSInt(CAT->getSize(),
true)) == 0;
603 "expecting a two-parameter std::span constructor");
606 auto HaveEqualConstantValues = [&Ctx](
const Expr *E0,
const Expr *E1) {
608 if (
auto E1CV = E1->getIntegerConstantExpr(Ctx)) {
609 return llvm::APSInt::compareValues(*E0CV, *E1CV) == 0;
613 auto AreSameDRE = [](
const Expr *E0,
const Expr *E1) {
614 if (
auto *DRE0 = dyn_cast<DeclRefExpr>(E0))
615 if (
auto *DRE1 = dyn_cast<DeclRefExpr>(E1)) {
616 return DRE0->getDecl() == DRE1->getDecl();
622 if (Arg1CV && Arg1CV->isZero())
628 case Stmt::CXXNewExprClass:
631 return AreSameDRE((*Size)->IgnoreImplicit(), Arg1) ||
632 HaveEqualConstantValues(*Size, Arg1);
637 return Arg1CV && Arg1CV->isOne();
645 if (
auto CCast = dyn_cast<CStyleCastExpr>(Arg0)) {
646 if (!CCast->getType()->isPointerType())
654 if (
const auto *
Call = dyn_cast<CallExpr>(CCast->getSubExpr())) {
656 if (
auto *AllocAttr = FD->getAttr<AllocSizeAttr>()) {
657 const Expr *EleSizeExpr =
658 Call->getArg(AllocAttr->getElemSizeParam().getASTIndex());
660 ParamIdx NumElemIdx = AllocAttr->getNumElemsParam();
667 if (
auto BO = dyn_cast<BinaryOperator>(Arg1))
674 auto IsMethodCallToSizedObject = [](
const Stmt *Node, StringRef MethodName) {
675 if (
const auto *MC = dyn_cast<CXXMemberCallExpr>(Node)) {
676 const auto *MD = MC->getMethodDecl();
677 const auto *RD = MC->getRecordDecl();
680 if (
auto *II = RD->getDeclName().getAsIdentifierInfo();
681 II && RD->isInStdNamespace())
684 MD->getName() == MethodName;
689 if (IsMethodCallToSizedObject(Arg0,
"begin") &&
690 IsMethodCallToSizedObject(Arg1,
"end"))
694 ->getImplicitObjectArgument()
695 ->IgnoreParenImpCasts(),
697 ->getImplicitObjectArgument()
698 ->IgnoreParenImpCasts());
706 const bool IgnoreStaticSizedArrays) {
715 if (
const auto *CATy =
716 dyn_cast<ConstantArrayType>(Node.
getBase()
720 limit = CATy->getLimitedSize();
721 }
else if (
const auto *SLiteral = dyn_cast<clang::StringLiteral>(
723 limit = SLiteral->getLength() + 1;
728 if (IgnoreStaticSizedArrays) {
738 llvm::APSInt ArrIdx = EVResult.
Val.
getInt();
741 if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit)
743 }
else if (
const auto *BE = dyn_cast<BinaryOperator>(IndexExpr)) {
746 if (BE->getOpcode() != BO_And && BE->getOpcode() != BO_Rem)
749 const Expr *LHS = BE->getLHS();
750 const Expr *RHS = BE->getRHS();
752 if (BE->getOpcode() == BO_Rem) {
759 llvm::APSInt result = EVResult.
Val.
getInt();
760 if (result.isNonNegative() && result.getLimitedValue() <= limit)
771 llvm::APSInt result = EVResult.
Val.
getInt();
772 if (result.isNonNegative() && result.getLimitedValue() < limit)
786 if (
const auto *CE = dyn_cast<ConditionalOperator>(E)) {
788 const auto *
Cond = CE->getCond();
790 if (!
Cond->isValueDependent() &&
791 Cond->EvaluateAsBooleanCondition(CondEval, Ctx))
792 return CondEval ? CE->getLHS() : CE->getRHS();
802 if (
const auto *DefaultArgE = dyn_cast<CXXDefaultArgExpr>(Ptr))
810 if (
const auto *CondE = dyn_cast<ConditionalOperator>(Ptr)) {
819 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Ptr)) {
829 static const llvm::StringSet<> NullTermFunctions = {
"strerror"};
830 if (
auto *CE = dyn_cast<CallExpr>(Ptr)) {
853 if (Name.ends_with(
"_s"))
854 return Name.drop_back(2 );
861 if (Name.starts_with(
"__") && Name.ends_with(
"_chk"))
863 Name.drop_front(2).drop_back(4) );
867static StringRef
matchName(StringRef FunName,
bool isBuiltin) {
869 if (isBuiltin && FunName.starts_with(
"__builtin_"))
873 FunName.drop_front(10 ));
875 if (FunName.starts_with(
"__asan_"))
892 const Expr *&UnsafeArg,
const unsigned FmtIdx,
893 std::optional<const unsigned> FmtArgIdx = std::nullopt,
894 bool isKprintf =
false) {
895 class StringFormatStringHandler
899 const Expr *&UnsafeArg;
915 unsigned PArgIdx = Precision.
getArgIndex() + FmtArgIdx;
917 if (PArgIdx < Call->getNumArgs()) {
918 const Expr *PArg =
Call->getArg(PArgIdx);
921 if (
auto *CE = dyn_cast<CastExpr>(PArg);
922 CE && CE->getType()->isSignedIntegerType())
923 PArg = CE->getSubExpr();
928 analyze_printf::OptionalAmount::HowSpecified::Constant) {
930 llvm::APSInt PArgVal = llvm::APSInt(
940 StringFormatStringHandler(
const CallExpr *
Call,
unsigned FmtArgIdx,
942 :
Call(
Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx),
943 UnsafeArgSet(
false) {}
946 const char *startSpecifier,
947 unsigned specifierLen,
955 if (ArgIdx >=
Call->getNumArgs())
959 const Expr *Arg =
Call->getArg(ArgIdx);
969 bool IsArgTypeValid =
972 ?
ArgType->getPointeeType()->isWideCharType()
973 :
ArgType->getPointeeType()->isCharType());
976 Precision && IsArgTypeValid)
980 UnsafeArg =
Call->getArg(ArgIdx);
985 bool isUnsafeArgSet() {
return UnsafeArgSet; }
988 const Expr *Fmt =
Call->getArg(FmtIdx);
989 unsigned FmtArgStartingIdx =
990 FmtArgIdx.has_value() ?
static_cast<unsigned>(*FmtArgIdx) : FmtIdx + 1;
993 if (SL->getCharByteWidth() == 1) {
994 StringRef FmtStr = SL->getString();
995 StringFormatStringHandler Handler(
Call, FmtArgStartingIdx, UnsafeArg,
999 Handler, FmtStr.begin(), FmtStr.end(), Ctx.
getLangOpts(),
1001 Handler.isUnsafeArgSet();
1004 if (
auto FmtStr = SL->tryEvaluateString(Ctx)) {
1005 StringFormatStringHandler Handler(
Call, FmtArgStartingIdx, UnsafeArg,
1008 Handler, FmtStr->data(), FmtStr->data() + FmtStr->size(),
1010 Handler.isUnsafeArgSet();
1016 return llvm::any_of(
1017 llvm::make_range(
Call->arg_begin() + FmtIdx,
Call->arg_end()),
1018 [&UnsafeArg, &Ctx](
const Expr *Arg) ->
bool {
1019 if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg, Ctx)) {
1037 static const std::set<StringRef> PredefinedNames = {
1116 if (PredefinedNames.count(Name))
1119 std::string NameWCS = Name.str();
1120 size_t WcsPos = NameWCS.find(
"wcs");
1122 while (WcsPos != std::string::npos) {
1123 NameWCS[WcsPos++] =
's';
1124 NameWCS[WcsPos++] =
't';
1125 NameWCS[WcsPos++] =
'r';
1126 WcsPos = NameWCS.find(
"wcs", WcsPos);
1128 if (PredefinedNames.count(NameWCS))
1132 return Name.ends_with(
"scanf");
1140 assert(FD &&
"It should have been checked that FD is non-null.");
1147 if (Name !=
"memset")
1159 const auto *AddressOfVar = dyn_cast_if_present<DeclRefExpr>(
1164 const auto *SizeOfVar =
1169 return AddressOfVar->getDecl() != SizeOfVar->getDecl();
1183 return Name.starts_with(
"v") && Name.ends_with(
"printf");
1196 return Name ==
"sprintf" || Name ==
"swprintf";
1210 if (!Name.ends_with(
"printf"))
1213 StringRef Prefix = Name.drop_back(6);
1215 if (Prefix.ends_with(
"w"))
1216 Prefix = Prefix.drop_back(1);
1218 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
1226 MatchResult &Result, llvm::StringRef Tag) {
1230 assert(FD &&
"It should have been checked that FD is non-null.");
1248 const Expr *UnsafeArg;
1259 bool isKprintf =
false;
1260 const Expr *UnsafeArg;
1263 isKprintf = II->getName() ==
"kprintf";
1265 std::nullopt, isKprintf)) {
1278 const Expr *UnsafeArg;
1289 for (
const auto *Arg : Node.
arguments())
1304 assert(FD &&
"It should have been checked that FD is non-null.");
1319 !Size->getType()->isUnsignedIntegerType())
1348#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1351 Gadget(Kind K) : K(K) {}
1353 Kind
getKind()
const {
return K; }
1356 StringRef getDebugName()
const {
1361#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1363 llvm_unreachable(
"Unhandled Gadget::Kind enum");
1367 virtual bool isWarningGadget()
const = 0;
1370 virtual SourceLocation getSourceLoc()
const = 0;
1375 virtual DeclUseList getClaimedVarUseSites()
const = 0;
1377 virtual ~Gadget() =
default;
1385class WarningGadget :
public Gadget {
1387 WarningGadget(Kind K) : Gadget(K) {}
1389 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1390 bool isWarningGadget() const final {
return true; }
1392 virtual void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1393 bool IsRelatedToDecl,
1394 ASTContext &Ctx)
const = 0;
1396 virtual SmallVector<const Expr *, 1> getUnsafePtrs()
const = 0;
1403class FixableGadget :
public Gadget {
1405 FixableGadget(Kind K) : Gadget(K) {}
1407 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1408 bool isWarningGadget() const final {
return false; }
1413 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1414 return std::nullopt;
1423 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1424 getStrategyImplications()
const {
1425 return std::nullopt;
1429static bool isSupportedVariable(
const DeclRefExpr &Node) {
1441 dyn_cast<ClassTemplateSpecializationDecl>(
RecordDecl);
1442 if (!class_template_specialization_decl)
1447 if (template_args.
size() == 0)
1458class UniquePtrArrayAccessGadget :
public WarningGadget {
1460 static constexpr const char *
const AccessorTag =
"unique_ptr_array_access";
1461 const CXXOperatorCallExpr *AccessorExpr;
1465 : WarningGadget(
Kind::UniquePtrArrayAccess),
1466 AccessorExpr(
Result.getNodeAs<CXXOperatorCallExpr>(AccessorTag)) {
1467 assert(AccessorExpr &&
1468 "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr");
1471 static bool classof(
const Gadget *G) {
1472 return G->getKind() == Kind::UniquePtrArrayAccess;
1475 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1478 const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(S);
1479 if (!OpCall || OpCall->
getOperator() != OO_Subscript)
1486 const CXXMethodDecl *
Method =
1491 if (
Method->getOverloadedOperator() != OO_Subscript)
1495 if (!isUniquePtrArray(RecordDecl))
1498 const Expr *IndexExpr = OpCall->
getArg(1);
1499 clang::Expr::EvalResult Eval;
1505 Result.addNode(AccessorTag, DynTypedNode::create(*OpCall));
1508 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1509 bool IsRelatedToDecl,
1510 ASTContext &Ctx)
const override {
1512 DynTypedNode::create(*AccessorExpr), IsRelatedToDecl, Ctx);
1515 SourceLocation getSourceLoc()
const override {
1517 return AccessorExpr->getOperatorLoc();
1518 return SourceLocation();
1521 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1522 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1525using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1526using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1530class IncrementGadget :
public WarningGadget {
1531 static constexpr const char *
const OpTag =
"op";
1532 const UnaryOperator *Op;
1536 : WarningGadget(
Kind::Increment),
1537 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1539 static bool classof(
const Gadget *G) {
1540 return G->getKind() == Kind::Increment;
1543 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1545 const auto *UO = dyn_cast<UnaryOperator>(S);
1550 Result.addNode(OpTag, DynTypedNode::create(*UO));
1554 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1555 bool IsRelatedToDecl,
1556 ASTContext &Ctx)
const override {
1559 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1561 DeclUseList getClaimedVarUseSites()
const override {
1562 SmallVector<const DeclRefExpr *, 2> Uses;
1563 if (
const auto *DRE =
1564 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1565 Uses.push_back(DRE);
1568 return std::move(Uses);
1571 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1572 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1578class DecrementGadget :
public WarningGadget {
1579 static constexpr const char *
const OpTag =
"op";
1580 const UnaryOperator *Op;
1584 : WarningGadget(
Kind::Decrement),
1585 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1587 static bool classof(
const Gadget *G) {
1588 return G->getKind() == Kind::Decrement;
1591 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1593 const auto *UO = dyn_cast<UnaryOperator>(S);
1598 Result.addNode(OpTag, DynTypedNode::create(*UO));
1602 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1603 bool IsRelatedToDecl,
1604 ASTContext &Ctx)
const override {
1607 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1609 DeclUseList getClaimedVarUseSites()
const override {
1610 if (
const auto *DRE =
1611 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1618 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1619 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1625class ArraySubscriptGadget :
public WarningGadget {
1626 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1627 const ArraySubscriptExpr *ASE;
1632 ASE(
Result.getNodeAs<ArraySubscriptExpr>(ArraySubscrTag)) {}
1634 static bool classof(
const Gadget *G) {
1635 return G->getKind() == Kind::ArraySubscript;
1638 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1639 const UnsafeBufferUsageHandler *Handler,
1641 const auto *ASE = dyn_cast<ArraySubscriptExpr>(S);
1644 const auto *
const Base = ASE->getBase()->IgnoreParenImpCasts();
1647 const auto *Idx = dyn_cast<IntegerLiteral>(ASE->getIdx());
1648 bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
1655 Result.addNode(ArraySubscrTag, DynTypedNode::create(*ASE));
1659 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1660 bool IsRelatedToDecl,
1661 ASTContext &Ctx)
const override {
1664 SourceLocation getSourceLoc()
const override {
return ASE->getBeginLoc(); }
1666 DeclUseList getClaimedVarUseSites()
const override {
1667 if (
const auto *DRE =
1668 dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
1675 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1676 return {ASE->getBase()->IgnoreParenImpCasts()};
1684class PointerArithmeticGadget :
public WarningGadget {
1685 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1686 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1687 const BinaryOperator *PA;
1692 : WarningGadget(
Kind::PointerArithmetic),
1693 PA(
Result.getNodeAs<BinaryOperator>(PointerArithmeticTag)),
1694 Ptr(
Result.getNodeAs<Expr>(PointerArithmeticPointerTag)) {}
1696 static bool classof(
const Gadget *G) {
1697 return G->getKind() == Kind::PointerArithmetic;
1700 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1702 const auto *BO = dyn_cast<BinaryOperator>(S);
1705 const auto *LHS = BO->
getLHS();
1706 const auto *RHS = BO->
getRHS();
1711 RHS->getType()->isEnumeralType())) {
1712 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*LHS));
1713 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1719 (LHS->getType()->isIntegerType() || LHS->getType()->isEnumeralType())) {
1720 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*RHS));
1721 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1727 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1728 bool IsRelatedToDecl,
1729 ASTContext &Ctx)
const override {
1732 SourceLocation getSourceLoc()
const override {
return PA->getBeginLoc(); }
1734 DeclUseList getClaimedVarUseSites()
const override {
1735 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts())) {
1742 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1743 return {Ptr->IgnoreParenImpCasts()};
1750class SpanTwoParamConstructorGadget :
public WarningGadget {
1751 static constexpr const char *
const SpanTwoParamConstructorTag =
1752 "spanTwoParamConstructor";
1753 const CXXConstructExpr *Ctor;
1757 : WarningGadget(
Kind::SpanTwoParamConstructor),
1758 Ctor(
Result.getNodeAs<CXXConstructExpr>(SpanTwoParamConstructorTag)) {}
1760 static bool classof(
const Gadget *G) {
1761 return G->getKind() == Kind::SpanTwoParamConstructor;
1765 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1768 const auto *CDecl = CE->getConstructor();
1769 const auto *CRecordDecl = CDecl->getParent();
1770 auto HasTwoParamSpanCtorDecl =
1771 CRecordDecl->isInStdNamespace() &&
1772 CDecl->getDeclName().getAsString() ==
"span" && CE->getNumArgs() == 2;
1775 Result.addNode(SpanTwoParamConstructorTag, DynTypedNode::create(*CE));
1779 static bool matches(
const Stmt *S, ASTContext &Ctx,
1780 const UnsafeBufferUsageHandler *Handler,
1787 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1788 bool IsRelatedToDecl,
1789 ASTContext &Ctx)
const override {
1792 SourceLocation getSourceLoc()
const override {
return Ctor->getBeginLoc(); }
1794 DeclUseList getClaimedVarUseSites()
const override {
1797 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->getArg(0))) {
1804 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1811class PointerInitGadget :
public FixableGadget {
1813 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1814 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1815 const VarDecl *PtrInitLHS;
1816 const DeclRefExpr *PtrInitRHS;
1820 : FixableGadget(
Kind::PointerInit),
1821 PtrInitLHS(
Result.getNodeAs<VarDecl>(PointerInitLHSTag)),
1822 PtrInitRHS(
Result.getNodeAs<DeclRefExpr>(PointerInitRHSTag)) {}
1824 static bool classof(
const Gadget *G) {
1825 return G->getKind() == Kind::PointerInit;
1828 static bool matches(
const Stmt *S,
1829 llvm::SmallVectorImpl<MatchResult> &Results) {
1830 const DeclStmt *DS = dyn_cast<DeclStmt>(S);
1839 const auto *DRE = dyn_cast<DeclRefExpr>(
Init->IgnoreImpCasts());
1840 if (!DRE || !
hasPointerType(*DRE) || !isSupportedVariable(*DRE)) {
1844 R.addNode(PointerInitLHSTag, DynTypedNode::create(*VD));
1845 R.addNode(PointerInitRHSTag, DynTypedNode::create(*DRE));
1846 Results.emplace_back(std::move(R));
1850 virtual std::optional<FixItList>
1851 getFixits(
const FixitStrategy &S)
const override;
1852 SourceLocation getSourceLoc()
const override {
1853 return PtrInitRHS->getBeginLoc();
1856 virtual DeclUseList getClaimedVarUseSites()
const override {
1857 return DeclUseList{PtrInitRHS};
1860 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1861 getStrategyImplications()
const override {
1862 return std::make_pair(PtrInitLHS,
cast<VarDecl>(PtrInitRHS->getDecl()));
1871class PtrToPtrAssignmentGadget :
public FixableGadget {
1873 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1874 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1875 const DeclRefExpr *PtrLHS;
1876 const DeclRefExpr *PtrRHS;
1880 : FixableGadget(
Kind::PtrToPtrAssignment),
1881 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1882 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1884 static bool classof(
const Gadget *G) {
1885 return G->getKind() == Kind::PtrToPtrAssignment;
1888 static bool matches(
const Stmt *S,
1889 llvm::SmallVectorImpl<MatchResult> &Results) {
1890 size_t SizeBefore = Results.size();
1892 const auto *BO = dyn_cast<BinaryOperator>(S);
1893 if (!BO || BO->
getOpcode() != BO_Assign)
1896 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1898 !isSupportedVariable(*RHSRef)) {
1901 const auto *LHS = BO->
getLHS();
1902 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1904 !isSupportedVariable(*LHSRef)) {
1908 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1909 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1910 Results.emplace_back(std::move(R));
1912 return SizeBefore != Results.size();
1915 virtual std::optional<FixItList>
1916 getFixits(
const FixitStrategy &S)
const override;
1917 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1919 virtual DeclUseList getClaimedVarUseSites()
const override {
1920 return DeclUseList{PtrLHS, PtrRHS};
1923 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1924 getStrategyImplications()
const override {
1935class CArrayToPtrAssignmentGadget :
public FixableGadget {
1937 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1938 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1939 const DeclRefExpr *PtrLHS;
1940 const DeclRefExpr *PtrRHS;
1944 : FixableGadget(
Kind::CArrayToPtrAssignment),
1945 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1946 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1948 static bool classof(
const Gadget *G) {
1949 return G->getKind() == Kind::CArrayToPtrAssignment;
1952 static bool matches(
const Stmt *S,
1953 llvm::SmallVectorImpl<MatchResult> &Results) {
1954 size_t SizeBefore = Results.size();
1956 const auto *BO = dyn_cast<BinaryOperator>(S);
1957 if (!BO || BO->
getOpcode() != BO_Assign)
1960 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1963 !isSupportedVariable(*RHSRef)) {
1966 const auto *LHS = BO->
getLHS();
1967 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1969 !isSupportedVariable(*LHSRef)) {
1973 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1974 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1975 Results.emplace_back(std::move(R));
1977 return SizeBefore != Results.size();
1980 virtual std::optional<FixItList>
1981 getFixits(
const FixitStrategy &S)
const override;
1982 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1984 virtual DeclUseList getClaimedVarUseSites()
const override {
1985 return DeclUseList{PtrLHS, PtrRHS};
1988 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1989 getStrategyImplications()
const override {
1996class UnsafeBufferUsageAttrGadget :
public WarningGadget {
1997 constexpr static const char *
const OpTag =
"attr_expr";
2002 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
2003 Op(
Result.getNodeAs<Expr>(OpTag)) {}
2005 static bool classof(
const Gadget *G) {
2006 return G->getKind() == Kind::UnsafeBufferUsageAttr;
2009 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2011 if (
auto *CE = dyn_cast<CallExpr>(S)) {
2012 if (CE->getDirectCallee() &&
2013 CE->getDirectCallee()->hasAttr<UnsafeBufferUsageAttr>()) {
2014 Result.addNode(OpTag, DynTypedNode::create(*CE));
2018 if (
auto *ME = dyn_cast<MemberExpr>(S)) {
2021 if (ME->getMemberDecl()->hasAttr<UnsafeBufferUsageAttr>()) {
2022 Result.addNode(OpTag, DynTypedNode::create(*ME));
2029 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2030 bool IsRelatedToDecl,
2031 ASTContext &Ctx)
const override {
2034 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2036 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2038 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2044class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
2045 constexpr static const char *
const OpTag =
"cxx_construct_expr";
2046 const CXXConstructExpr *Op;
2050 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
2051 Op(
Result.getNodeAs<CXXConstructExpr>(OpTag)) {}
2053 static bool classof(
const Gadget *G) {
2054 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
2058 const auto *CE = dyn_cast<CXXConstructExpr>(S);
2059 if (!CE || !CE->getConstructor()->hasAttr<UnsafeBufferUsageAttr>())
2063 if (SpanTwoParamConstructorGadget::matches(CE, Ctx, Tmp))
2065 Result.addNode(OpTag, DynTypedNode::create(*CE));
2069 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2070 bool IsRelatedToDecl,
2071 ASTContext &Ctx)
const override {
2074 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2076 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2078 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2085class DataInvocationGadget :
public WarningGadget {
2086 constexpr static const char *
const OpTag =
"data_invocation_expr";
2087 const ExplicitCastExpr *Op;
2091 : WarningGadget(
Kind::DataInvocation),
2092 Op(
Result.getNodeAs<ExplicitCastExpr>(OpTag)) {}
2094 static bool classof(
const Gadget *G) {
2095 return G->getKind() == Kind::DataInvocation;
2098 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2100 auto *CE = dyn_cast<ExplicitCastExpr>(S);
2103 for (
auto *Child : CE->children()) {
2104 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Child);
2105 MCE && isDataFunction(MCE)) {
2106 Result.addNode(OpTag, DynTypedNode::create(*CE));
2109 if (
auto *
Paren = dyn_cast<ParenExpr>(Child)) {
2110 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(
Paren->getSubExpr());
2111 MCE && isDataFunction(MCE)) {
2112 Result.addNode(OpTag, DynTypedNode::create(*CE));
2120 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2121 bool IsRelatedToDecl,
2122 ASTContext &Ctx)
const override {
2125 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2127 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2130 static bool isDataFunction(
const CXXMemberCallExpr *call) {
2137 if (method->getNameAsString() ==
"data" &&
2138 method->getParent()->isInStdNamespace() &&
2139 llvm::is_contained({SIZED_CONTAINER_OR_VIEW_LIST},
2140 method->getParent()->getName()))
2145 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2148class UnsafeLibcFunctionCallGadget :
public WarningGadget {
2149 const CallExpr *
const Call;
2150 const Expr *UnsafeArg =
nullptr;
2151 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
2153 constexpr static const char *
const UnsafeSprintfTag =
2154 "UnsafeLibcFunctionCall_sprintf";
2155 constexpr static const char *
const UnsafeSizedByTag =
2156 "UnsafeLibcFunctionCall_sized_by";
2157 constexpr static const char *
const UnsafeStringTag =
2158 "UnsafeLibcFunctionCall_string";
2159 constexpr static const char *
const UnsafeVaListTag =
2160 "UnsafeLibcFunctionCall_va_list";
2174 } WarnedFunKind = OTHERS;
2177 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2178 Call(
Result.getNodeAs<CallExpr>(Tag)) {
2179 if (
Result.getNodeAs<Decl>(UnsafeSprintfTag))
2180 WarnedFunKind = SPRINTF;
2181 else if (
auto *E =
Result.getNodeAs<Expr>(UnsafeStringTag)) {
2182 WarnedFunKind = STRING;
2184 }
else if (
Result.getNodeAs<CallExpr>(UnsafeSizedByTag)) {
2185 WarnedFunKind = SIZED_BY;
2186 UnsafeArg = Call->getArg(0);
2187 }
else if (
Result.getNodeAs<Decl>(UnsafeVaListTag))
2188 WarnedFunKind = VA_LIST;
2191 static bool matches(
const Stmt *S, ASTContext &Ctx,
2192 const UnsafeBufferUsageHandler *Handler,
2196 const auto *CE = dyn_cast<CallExpr>(S);
2199 const auto *FD = CE->getDirectCallee();
2203 const bool IsGlobalAndNotInAnyNamespace =
2204 FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
2208 if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
2215 const bool isSingleStringLiteralArg =
2216 CE->getNumArgs() == 1 &&
2218 if (!isSingleStringLiteralArg) {
2221 Result.addNode(Tag, DynTypedNode::create(*CE));
2225 Result.addNode(Tag, DynTypedNode::create(*CE));
2229 Result.addNode(Tag, DynTypedNode::create(*CE));
2230 Result.addNode(UnsafeVaListTag, DynTypedNode::create(*FD));
2234 Result.addNode(Tag, DynTypedNode::create(*CE));
2235 Result.addNode(UnsafeSprintfTag, DynTypedNode::create(*FD));
2241 Result.addNode(Tag, DynTypedNode::create(*CE));
2242 Result.addNode(UnsafeSizedByTag, DynTypedNode::create(*CE));
2247 Result.addNode(Tag, DynTypedNode::create(*CE));
2254 const Stmt *getBaseStmt()
const {
return Call; }
2256 SourceLocation getSourceLoc()
const override {
return Call->getBeginLoc(); }
2258 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2259 bool IsRelatedToDecl,
2260 ASTContext &Ctx)
const override {
2264 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2266 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2269class UnsafeFormatAttributedFunctionCallGadget :
public WarningGadget {
2270 const CallExpr *
const Call;
2271 const Expr *UnsafeArg =
nullptr;
2272 constexpr static const char *
const Tag =
"UnsafeFormatAttributedFunctionCall";
2273 constexpr static const char *
const UnsafeStringTag =
2274 "UnsafeFormatAttributedFunctionCall_string";
2278 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2279 Call(
Result.getNodeAs<CallExpr>(Tag)),
2280 UnsafeArg(
Result.getNodeAs<Expr>(UnsafeStringTag)) {}
2282 static bool matches(
const Stmt *S, ASTContext &Ctx,
2283 const UnsafeBufferUsageHandler *Handler,
2287 auto *CE = dyn_cast<CallExpr>(S);
2288 if (!CE || !CE->getDirectCallee())
2290 const FunctionDecl *FD = CE->getDirectCallee();
2294 const FormatAttr *Attr =
nullptr;
2295 bool IsPrintf =
false;
2296 bool AnyAttr = llvm::any_of(
2298 [&Attr, &IsPrintf](
const FormatAttr *FA) ->
bool {
2299 if (const auto *II = FA->getType()) {
2300 if (II->getName() ==
"printf" || II->getName() ==
"scanf") {
2302 IsPrintf = II->getName() ==
"printf";
2308 const Expr *UnsafeArg;
2314 unsigned FmtIdx = Attr->getFormatIdx() - 1;
2315 std::optional<unsigned> FmtArgIdx = Attr->getFirstArg() - 1;
2325 }
else if (CE->getStmtClass() != Stmt::CallExprClass &&
2328 if (*FmtArgIdx >= CE->getNumArgs())
2335 FmtArgIdx = std::nullopt;
2337 if (AnyAttr && !IsPrintf && FmtArgIdx) {
2339 Result.addNode(Tag, DynTypedNode::create(*CE));
2344 Ctx, CE, UnsafeArg, FmtIdx, FmtArgIdx)) {
2345 Result.addNode(Tag, DynTypedNode::create(*CE));
2346 Result.addNode(UnsafeStringTag, DynTypedNode::create(*UnsafeArg));
2352 const Stmt *getBaseStmt()
const {
return Call; }
2357 bool IsRelatedToDecl,
2362 UnsafeLibcFunctionCallGadget::UnsafeKind::STRING |
2363 UnsafeLibcFunctionCallGadget::UnsafeKind::FORMAT_ATTR,
2368 UnsafeLibcFunctionCallGadget::UnsafeKind::OTHERS |
2369 UnsafeLibcFunctionCallGadget::UnsafeKind::FORMAT_ATTR,
2373 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2381class ULCArraySubscriptGadget :
public FixableGadget {
2383 static constexpr const char *
const ULCArraySubscriptTag =
2384 "ArraySubscriptUnderULC";
2385 const ArraySubscriptExpr *Node;
2389 : FixableGadget(
Kind::ULCArraySubscript),
2390 Node(
Result.getNodeAs<ArraySubscriptExpr>(ULCArraySubscriptTag)) {
2391 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2394 static bool classof(
const Gadget *G) {
2395 return G->getKind() == Kind::ULCArraySubscript;
2398 static bool matches(
const Stmt *S,
2399 llvm::SmallVectorImpl<MatchResult> &Results) {
2400 size_t SizeBefore = Results.size();
2402 const auto *ASE = dyn_cast<ArraySubscriptExpr>(E);
2408 !isSupportedVariable(*DRE))
2411 R.addNode(ULCArraySubscriptTag, DynTypedNode::create(*ASE));
2412 Results.emplace_back(std::move(R));
2414 return SizeBefore != Results.size();
2417 virtual std::optional<FixItList>
2418 getFixits(
const FixitStrategy &S)
const override;
2419 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2421 virtual DeclUseList getClaimedVarUseSites()
const override {
2422 if (
const auto *DRE =
2423 dyn_cast<DeclRefExpr>(Node->getBase()->IgnoreImpCasts())) {
2433class UPCStandalonePointerGadget :
public FixableGadget {
2435 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
2436 const DeclRefExpr *Node;
2440 : FixableGadget(
Kind::UPCStandalonePointer),
2441 Node(
Result.getNodeAs<DeclRefExpr>(DeclRefExprTag)) {
2442 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2445 static bool classof(
const Gadget *G) {
2446 return G->getKind() == Kind::UPCStandalonePointer;
2449 static bool matches(
const Stmt *S,
2450 llvm::SmallVectorImpl<MatchResult> &Results) {
2451 size_t SizeBefore = Results.size();
2453 auto *E = dyn_cast<Expr>(S);
2458 !isSupportedVariable(*DRE))
2461 R.addNode(DeclRefExprTag, DynTypedNode::create(*DRE));
2462 Results.emplace_back(std::move(R));
2464 return SizeBefore != Results.size();
2467 virtual std::optional<FixItList>
2468 getFixits(
const FixitStrategy &S)
const override;
2469 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2471 virtual DeclUseList getClaimedVarUseSites()
const override {
return {Node}; }
2474class PointerDereferenceGadget :
public FixableGadget {
2475 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2476 static constexpr const char *
const OperatorTag =
"op";
2478 const DeclRefExpr *BaseDeclRefExpr =
nullptr;
2479 const UnaryOperator *Op =
nullptr;
2483 : FixableGadget(
Kind::PointerDereference),
2484 BaseDeclRefExpr(
Result.getNodeAs<DeclRefExpr>(BaseDeclRefExprTag)),
2485 Op(
Result.getNodeAs<UnaryOperator>(OperatorTag)) {}
2487 static bool classof(
const Gadget *G) {
2488 return G->getKind() == Kind::PointerDereference;
2491 static bool matches(
const Stmt *S,
2492 llvm::SmallVectorImpl<MatchResult> &Results) {
2493 size_t SizeBefore = Results.size();
2495 const auto *UO = dyn_cast<UnaryOperator>(S);
2502 const auto *DRE = dyn_cast<DeclRefExpr>(CE);
2503 if (!DRE || !isSupportedVariable(*DRE))
2506 R.addNode(BaseDeclRefExprTag, DynTypedNode::create(*DRE));
2507 R.addNode(OperatorTag, DynTypedNode::create(*UO));
2508 Results.emplace_back(std::move(R));
2510 return SizeBefore != Results.size();
2513 DeclUseList getClaimedVarUseSites()
const override {
2514 return {BaseDeclRefExpr};
2517 virtual std::optional<FixItList>
2518 getFixits(
const FixitStrategy &S)
const override;
2519 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2525class UPCAddressofArraySubscriptGadget :
public FixableGadget {
2527 static constexpr const char *
const UPCAddressofArraySubscriptTag =
2528 "AddressofArraySubscriptUnderUPC";
2529 const UnaryOperator *Node;
2533 : FixableGadget(
Kind::ULCArraySubscript),
2534 Node(
Result.getNodeAs<UnaryOperator>(UPCAddressofArraySubscriptTag)) {
2535 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2538 static bool classof(
const Gadget *G) {
2539 return G->getKind() == Kind::UPCAddressofArraySubscript;
2542 static bool matches(
const Stmt *S,
2543 llvm::SmallVectorImpl<MatchResult> &Results) {
2544 size_t SizeBefore = Results.size();
2546 auto *E = dyn_cast<Expr>(S);
2550 if (!UO || UO->
getOpcode() != UO_AddrOf)
2552 const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->
getSubExpr());
2557 if (!DRE || !isSupportedVariable(*DRE))
2560 R.addNode(UPCAddressofArraySubscriptTag, DynTypedNode::create(*UO));
2561 Results.emplace_back(std::move(R));
2563 return SizeBefore != Results.size();
2566 virtual std::optional<FixItList>
2567 getFixits(
const FixitStrategy &)
const override;
2568 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2570 virtual DeclUseList getClaimedVarUseSites()
const override {
2583class DeclUseTracker {
2584 using UseSetTy = llvm::SmallPtrSet<const DeclRefExpr *, 16>;
2585 using DefMapTy = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
2588 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
2592 DeclUseTracker() =
default;
2593 DeclUseTracker(
const DeclUseTracker &) =
delete;
2594 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
2595 DeclUseTracker(DeclUseTracker &&) =
default;
2596 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
2599 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
2602 void claimUse(
const DeclRefExpr *DRE) {
2603 assert(Uses->count(DRE) &&
2604 "DRE not found or claimed by multiple matchers!");
2609 bool hasUnclaimedUses(
const VarDecl *VD)
const {
2611 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
2616 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
2618 for (
auto use : *Uses) {
2620 ReturnSet.insert(use);
2626 void discoverDecl(
const DeclStmt *DS) {
2627 for (
const Decl *D : DS->
decls()) {
2628 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
2639 const DeclStmt *lookupDecl(
const VarDecl *VD)
const {
2640 return Defs.lookup(VD);
2649 static constexpr const char *
const UPCPreIncrementTag =
2650 "PointerPreIncrementUnderUPC";
2655 : FixableGadget(Kind::UPCPreIncrement),
2657 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2661 return G->getKind() == Kind::UPCPreIncrement;
2670 size_t SizeBefore = Results.size();
2672 auto *E = dyn_cast<Expr>(S);
2676 if (!UO || UO->
getOpcode() != UO_PreInc)
2678 const auto *DRE = dyn_cast<DeclRefExpr>(UO->
getSubExpr());
2679 if (!DRE || !isSupportedVariable(*DRE))
2683 Results.emplace_back(std::move(R));
2685 return SizeBefore != Results.size();
2688 virtual std::optional<FixItList>
2693 return {dyn_cast<DeclRefExpr>(Node->getSubExpr())};
2701 static constexpr const char *
const UUCAddAssignTag =
2702 "PointerAddAssignUnderUUC";
2703 static constexpr const char *
const OffsetTag =
"Offset";
2706 const Expr *Offset =
nullptr;
2710 : FixableGadget(Kind::UUCAddAssign),
2713 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2717 return G->getKind() == Kind::UUCAddAssign;
2722 size_t SizeBefore = Results.size();
2724 const auto *E = dyn_cast<Expr>(S);
2728 if (!BO || BO->
getOpcode() != BO_AddAssign)
2730 const auto *DRE = dyn_cast<DeclRefExpr>(BO->
getLHS());
2736 Results.emplace_back(std::move(R));
2738 return SizeBefore != Results.size();
2741 virtual std::optional<FixItList>
2746 return {dyn_cast<DeclRefExpr>(Node->getLHS())};
2753 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2754 static constexpr const char *
const DerefOpTag =
"DerefOp";
2755 static constexpr const char *
const AddOpTag =
"AddOp";
2756 static constexpr const char *
const OffsetTag =
"Offset";
2765 : FixableGadget(Kind::DerefSimplePtrArithFixable),
2773 auto IsPtr = [](
const Expr *E, MatchResult &R) {
2777 if (!DRE || !isSupportedVariable(*DRE))
2782 const auto IsPlusOverPtrAndInteger = [&IsPtr](
const Expr *E,
2784 const auto *BO = dyn_cast<BinaryOperator>(E);
2788 const auto *LHS = BO->
getLHS();
2789 const auto *RHS = BO->
getRHS();
2802 size_t SizeBefore = Results.size();
2803 const auto InnerMatcher = [&IsPlusOverPtrAndInteger,
2804 &Results](
const Expr *E) {
2805 const auto *UO = dyn_cast<UnaryOperator>(E);
2811 if (IsPlusOverPtrAndInteger(Operand, R)) {
2813 Results.emplace_back(std::move(R));
2817 return SizeBefore != Results.size();
2820 virtual std::optional<FixItList>
2823 return DerefOp->getBeginLoc();
2827 return {BaseDeclRefExpr};
2835 : WarningGadgets(WarningGadgets) {}
2844#define WARNING_GADGET(name) \
2845 if (name##Gadget::matches(S, Ctx, Result) && \
2846 notInSafeBufferOptOut(*S, &Handler)) { \
2847 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2850#define WARNING_OPTIONAL_GADGET(name) \
2851 if (name##Gadget::matches(S, Ctx, &Handler, Result) && \
2852 notInSafeBufferOptOut(*S, &Handler)) { \
2853 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2856#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2861 WarningGadgetList &WarningGadgets;
2868 DeclUseTracker &Tracker)
2869 : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
2873 bool matchFound =
false;
2880#define FIXABLE_GADGET(name) \
2881 if (name##Gadget::matches(S, Results)) { \
2882 for (const auto &R : Results) { \
2883 FixableGadgets.push_back(std::make_unique<name##Gadget>(R)); \
2884 matchFound = true; \
2888#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2891 if (
auto *DRE = findDeclRefExpr(S); DRE) {
2892 Tracker.discoverUse(DRE);
2898 if (
auto *DS = findDeclStmt(S); DS) {
2899 Tracker.discoverDecl(DS);
2907 const auto *DRE = dyn_cast<DeclRefExpr>(S);
2915 const DeclStmt *findDeclStmt(
const Stmt *S) {
2916 const auto *DS = dyn_cast<DeclStmt>(S);
2921 FixableGadgetList &FixableGadgets;
2922 DeclUseTracker &Tracker;
2928 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2929 WarningGadgetList &WarningGadgets,
2930 DeclUseTracker &Tracker) {
2933 if (EmitSuggestions) {
2942 return N1->getBeginLoc().getRawEncoding() <
2943 N2->getBeginLoc().getRawEncoding();
2956 auto AddStmt = [&Stmts](
const Stmt *S) {
2960 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
2963 if (PD->hasDefaultArg() && !PD->hasUninstantiatedDefaultArg())
2964 AddStmt(PD->getDefaultArg());
2965 if (
const auto *CtorD = dyn_cast<CXXConstructorDecl>(FD))
2967 Stmts, llvm::map_range(CtorD->inits(),
2971 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
2973 }
else if (
const auto *FD = dyn_cast<FieldDecl>(D)) {
2974 AddStmt(FD->getInClassInitializer());
2984 const Expr *UnsafeArg =
nullptr)
override {}
2992 bool IsRelatedToDecl,
3013 FixableGadgetList FixableGadgets;
3014 WarningGadgetList WarningGadgets;
3015 DeclUseTracker Tracker;
3016 MockReporter IgnoreHandler;
3021 for (
auto *
Stmt : Stmts)
3022 findGadgets(
Stmt, Ctx, IgnoreHandler,
false, FixableGadgets, WarningGadgets,
3025 std::set<const Expr *>
Result;
3026 for (
auto &G : WarningGadgets) {
3027 for (
const Expr *E : G->getUnsafePtrs()) {
3036 std::map<const VarDecl *, std::set<const WarningGadget *>,
3050 for (
auto &G : AllUnsafeOperations) {
3051 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
3053 bool AssociatedWithVarDecl =
false;
3054 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
3055 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3056 result.
byVar[VD].insert(G.get());
3057 AssociatedWithVarDecl =
true;
3061 if (!AssociatedWithVarDecl) {
3062 result.
noVar.push_back(G.get());
3070 std::map<const VarDecl *, std::set<const FixableGadget *>,
3080 for (
auto &F : AllFixableOperations) {
3081 DeclUseList DREs = F->getClaimedVarUseSites();
3084 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3085 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
3089 return FixablesForUnsafeVars;
3096 std::vector<const FixItHint *>
All;
3100 std::sort(
All.begin(),
All.end(),
3102 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
3103 H2->RemoveRange.getBegin());
3111 Hint->RemoveRange.getBegin())) {
3123std::optional<FixItList>
3124PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
3127 switch (S.
lookup(LeftVD)) {
3131 return std::nullopt;
3133 return std::nullopt;
3136 return std::nullopt;
3138 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3140 return std::nullopt;
3144static inline std::optional<FixItList>
createDataFixit(
const ASTContext &Ctx,
3145 const DeclRefExpr *DRE);
3147std::optional<FixItList>
3148CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
3167 if (S.
lookup(LeftVD) == FixitStrategy::Kind::Span) {
3168 if (S.
lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
3171 }
else if (S.
lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
3172 if (S.
lookup(RightVD) == FixitStrategy::Kind::Array) {
3176 return std::nullopt;
3179std::optional<FixItList>
3180PointerInitGadget::getFixits(
const FixitStrategy &S)
const {
3181 const auto *LeftVD = PtrInitLHS;
3183 switch (S.
lookup(LeftVD)) {
3184 case FixitStrategy::Kind::Span:
3185 if (S.
lookup(RightVD) == FixitStrategy::Kind::Span)
3187 return std::nullopt;
3188 case FixitStrategy::Kind::Wontfix:
3189 return std::nullopt;
3190 case FixitStrategy::Kind::Iterator:
3191 case FixitStrategy::Kind::Array:
3192 return std::nullopt;
3193 case FixitStrategy::Kind::Vector:
3194 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3196 return std::nullopt;
3202 if (ConstVal->isNegative())
3209std::optional<FixItList>
3210ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
3211 if (
const auto *DRE =
3213 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3215 case FixitStrategy::Kind::Span: {
3219 const ASTContext &Ctx =
3222 return std::nullopt;
3226 case FixitStrategy::Kind::Array:
3228 case FixitStrategy::Kind::Wontfix:
3229 case FixitStrategy::Kind::Iterator:
3230 case FixitStrategy::Kind::Vector:
3231 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3234 return std::nullopt;
3237static std::optional<FixItList>
3240std::optional<FixItList>
3241UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
3242 auto DREs = getClaimedVarUseSites();
3246 case FixitStrategy::Kind::Span:
3248 case FixitStrategy::Kind::Wontfix:
3249 case FixitStrategy::Kind::Iterator:
3250 case FixitStrategy::Kind::Array:
3251 return std::nullopt;
3252 case FixitStrategy::Kind::Vector:
3253 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3255 return std::nullopt;
3260 static const char *
const EOL =
"\n";
3267 std::string
s = std::string(
"<# ");
3268 s += HintTextToUser;
3274template <
typename NodeTy>
3275static std::optional<SourceLocation>
3278 if (
unsigned TkLen =
3285 return std::nullopt;
3298 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
3299 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
3300 VD->getBeginLoc())) &&
3301 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
3302 At->getRange().getBegin()));
3306 AttrRangeOverlapping;
3348 std::optional<Qualifiers> Quals = std::nullopt) {
3349 const char *
const SpanOpen =
"std::span<";
3352 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
3353 return SpanOpen + EltTyText.str() +
'>';
3356std::optional<FixItList>
3358 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->getDecl());
3363 if (
auto ConstVal = Offset->getIntegerConstantExpr(Ctx))
3364 if (ConstVal->isNegative())
3365 return std::nullopt;
3386 const Expr *LHS = AddOp->getLHS(), *RHS = AddOp->getRHS();
3393 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
3395 return std::nullopt;
3400 std::optional<SourceLocation> AddOpLocation =
3402 std::optional<SourceLocation> DerefOpLocation =
3405 if (!AddOpLocation || !DerefOpLocation)
3406 return std::nullopt;
3416 return std::nullopt;
3419std::optional<FixItList>
3420PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
3431 if (
auto LocPastOperand =
3438 case FixitStrategy::Kind::Iterator:
3439 case FixitStrategy::Kind::Array:
3440 return std::nullopt;
3441 case FixitStrategy::Kind::Vector:
3442 llvm_unreachable(
"FixitStrategy not implemented yet!");
3443 case FixitStrategy::Kind::Wontfix:
3444 llvm_unreachable(
"Invalid strategy!");
3447 return std::nullopt;
3454 std::optional<SourceLocation> EndOfOperand =
3460 return std::nullopt;
3465std::optional<FixItList>
3466UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
3469 case FixitStrategy::Kind::Array:
3470 case FixitStrategy::Kind::Span: {
3475 case FixitStrategy::Kind::Wontfix:
3476 case FixitStrategy::Kind::Iterator:
3477 return std::nullopt;
3478 case FixitStrategy::Kind::Vector:
3479 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3482 return std::nullopt;
3487static std::optional<FixItList>
3494 const Expr *Idx = ArraySub->getIdx();
3497 std::stringstream SS;
3498 bool IdxIsLitZero =
false;
3501 if ((*ICE).isZero())
3502 IdxIsLitZero =
true;
3503 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
3505 return std::nullopt;
3509 SS << (*DreString).str() <<
".data()";
3511 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
3513 return std::nullopt;
3515 SS <<
"&" << (*DreString).str() <<
".data()"
3516 <<
"[" << (*IndexString).str() <<
"]";
3522std::optional<FixItList>
3526 if (DREs.size() != 1)
3527 return std::nullopt;
3529 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3533 const Stmt *AddAssignNode = Node;
3534 StringRef varName = VD->
getName();
3538 return std::nullopt;
3542 (Offset->IgnoreParens()->getBeginLoc() == Offset->getBeginLoc());
3543 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
3547 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
3549 if (!AddAssignLocation)
3550 return std::nullopt;
3557 Offset->getEndLoc().getLocWithOffset(1),
")"));
3561 return std::nullopt;
3564std::optional<FixItList>
3568 if (DREs.size() != 1)
3569 return std::nullopt;
3571 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3574 std::stringstream SS;
3575 StringRef varName = VD->
getName();
3579 SS <<
"(" << varName.data() <<
" = " << varName.data()
3580 <<
".subspan(1)).data()";
3581 std::optional<SourceLocation> PreIncLocation =
3583 if (!PreIncLocation)
3584 return std::nullopt;
3587 SourceRange(Node->getBeginLoc(), *PreIncLocation), SS.str()));
3591 return std::nullopt;
3609static std::optional<FixItList>
3611 const StringRef UserFillPlaceHolder) {
3619 if (
Init->isNullPointerConstant(
3624 NPC_ValueDependentIsNotNull)) {
3625 std::optional<SourceLocation> InitLocation =
3628 return std::nullopt;
3636 std::string ExtentText = UserFillPlaceHolder.data();
3637 StringRef One =
"1";
3642 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
3647 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
3648 if (!Ext->HasSideEffects(Ctx)) {
3649 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
3651 return std::nullopt;
3652 ExtentText = *ExtentString;
3654 }
else if (!CxxNew->isArray())
3666 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
3667 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
3668 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
3675 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
3678 return std::nullopt;
3680 StrBuffer.append(
", ");
3681 StrBuffer.append(ExtentText);
3682 StrBuffer.append(
"}");
3688#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
3689 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
3690 "failed to produce fixit for declaration '" + \
3691 (D)->getNameAsString() + "'" + (Msg))
3693#define DEBUG_NOTE_DECL_FAIL(D, Msg)
3699static std::optional<std::string>
3703 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3708 return std::nullopt;
3710 std::string SpanTyText =
"std::span<";
3712 SpanTyText.append(*PteTyText);
3714 if (PteTyQualifiers) {
3715 SpanTyText.append(
" ");
3716 SpanTyText.append(PteTyQualifiers->getAsString());
3718 SpanTyText.append(
">");
3737 const StringRef UserFillPlaceHolder,
3751 std::stringstream SS;
3756 std::optional<FixItList> InitFixIts =
3760 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
3761 std::make_move_iterator(InitFixIts->end()));
3768 if (!EndLocForReplacement.
isValid()) {
3818static std::optional<FixItList>
3824 return std::nullopt;
3829 std::vector<std::string> NewTysTexts(NumParms);
3830 std::vector<bool> ParmsMask(NumParms,
false);
3831 bool AtLeastOneParmToFix =
false;
3833 for (
unsigned i = 0; i < NumParms; i++) {
3840 return std::nullopt;
3842 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3843 std::optional<std::string> PteTyText =
3848 return std::nullopt;
3852 ParmsMask[i] =
true;
3853 AtLeastOneParmToFix =
true;
3855 if (!AtLeastOneParmToFix)
3862 const auto NewOverloadSignatureCreator =
3863 [&
SM, &LangOpts, &NewTysTexts,
3864 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3865 std::stringstream SS;
3873 SS << Prefix->str();
3875 return std::nullopt;
3879 for (
unsigned i = 0; i < NumParms; i++) {
3887 SS << NewTysTexts[i];
3890 SS <<
' ' << II->getName().str();
3891 }
else if (
auto ParmTypeText =
3895 SS << ParmTypeText->str();
3897 return std::nullopt;
3898 if (i != NumParms - 1)
3907 const auto OldOverloadDefCreator =
3908 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3909 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3910 std::stringstream SS;
3918 << FDPrefix->str() <<
"{";
3920 return std::nullopt;
3923 SS <<
"return " << FunQualName->str() <<
"(";
3925 return std::nullopt;
3929 for (
unsigned i = 0; i < NumParms; i++) {
3938 return std::nullopt;
3945 if (i != NumParms - 1)
3956 std::optional<SourceLocation> Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3960 if (FReDecl->isThisDeclarationADefinition()) {
3961 assert(FReDecl == FD &&
"inconsistent function definition");
3964 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3970 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3973 FReDecl->getBeginLoc(),
" ")));
3976 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3998 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
4014 std::stringstream SS;
4017 if (PteTyQualifiers)
4026 SS <<
' ' << PVDNameText->str();
4032 const DeclUseTracker &Tracker,
4035 const DeclStmt *DS = Tracker.lookupDecl(VD);
4038 " : variables declared this way not implemented yet");
4062 const QualType &ArrayEltT = CAT->getElementType();
4063 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
4072 auto MaybeElemTypeTxt =
4075 if (!MaybeElemTypeTxt)
4077 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
4082 while (NextTok && !NextTok->is(tok::l_square) &&
4095 if (!MaybeArraySizeTxt)
4097 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
4098 if (ArraySizeTxt.empty()) {
4109 std::optional<StringRef> IdentText =
4118 llvm::raw_svector_ostream OS(Replacement);
4119 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
4120 << IdentText->str();
4130 const DeclUseTracker &Tracker,
4133 const DeclStmt *DS = Tracker.lookupDecl(VD);
4134 assert(DS &&
"Fixing non-local variables not implemented yet!");
4153 const DeclUseTracker &Tracker,
ASTContext &Ctx,
4155 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
4156 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
4157 if (!FD || FD != D) {
4184 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
4202 llvm_unreachable(
"FixitStrategy not implemented yet!");
4204 llvm_unreachable(
"Invalid strategy!");
4206 llvm_unreachable(
"Unknown strategy!");
4214 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
4216 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
4233 std::map<const VarDecl *, FixItList> &FixItsForVariable,
4238 for (
const auto &[VD, Ignore] : FixItsForVariable) {
4240 if (llvm::any_of(Grp,
4241 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
4242 return !FixItsForVariable.count(GrpMember);
4247 ToErase.push_back(
Member);
4250 for (
auto *VarToErase : ToErase)
4251 FixItsForVariable.erase(VarToErase);
4262 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
4266 FixItList FixItsSharedByParms{};
4268 std::optional<FixItList> OverloadFixes =
4271 if (OverloadFixes) {
4272 FixItsSharedByParms.append(*OverloadFixes);
4278 FixItsForVariable.erase(
Member);
4280 return FixItsSharedByParms;
4284static std::map<const VarDecl *, FixItList>
4293 std::map<const VarDecl *, FixItList> FixItsForVariable;
4298 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
4299 FixItsForVariable[VD] =
4303 if (FixItsForVariable[VD].empty()) {
4304 FixItsForVariable.erase(VD);
4307 for (
const auto &F : Fixables) {
4308 std::optional<FixItList> Fixits = F->getFixits(S);
4311 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
4312 Fixits->begin(), Fixits->end());
4317 VD, F->getSourceLoc(),
4318 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
4321 FixItsForVariable.erase(VD);
4340 FixItList FixItsSharedByParms{};
4342 if (
auto *FD = dyn_cast<FunctionDecl>(D))
4344 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
4348 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
4351 for (
auto &[Var, Ignore] : FixItsForVariable) {
4352 bool AnyParm =
false;
4353 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
4355 for (
const VarDecl *GrpMate : VarGroupForVD) {
4358 if (FixItsForVariable.count(GrpMate))
4359 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
4363 assert(!FixItsSharedByParms.empty() &&
4364 "Should not try to fix a parameter that does not belong to a "
4366 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
4373 for (
auto Iter = FinalFixItsForVariable.begin();
4374 Iter != FinalFixItsForVariable.end();)
4377 Iter = FinalFixItsForVariable.erase(Iter);
4380 return FinalFixItsForVariable;
4383template <
typename VarDeclIterTy>
4387 for (
const VarDecl *VD : UnsafeVars) {
4398 const std::vector<VarGrpTy> &Groups;
4399 const std::map<const VarDecl *, unsigned> &VarGrpMap;
4400 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
4404 const std::vector<VarGrpTy> &Groups,
4405 const std::map<const VarDecl *, unsigned> &VarGrpMap,
4406 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
4407 : Groups(Groups), VarGrpMap(VarGrpMap),
4408 GrpsUnionForParms(GrpsUnionForParms) {}
4411 if (GrpsUnionForParms.contains(Var)) {
4414 return GrpsUnionForParms.getArrayRef();
4419 auto It = VarGrpMap.find(Var);
4421 if (It == VarGrpMap.end())
4423 return Groups[It->second];
4427 return GrpsUnionForParms.getArrayRef();
4432 WarningGadgetList WarningGadgets,
4433 DeclUseTracker Tracker,
4435 bool EmitSuggestions) {
4436 if (!EmitSuggestions) {
4440 for (
const auto &G : WarningGadgets) {
4441 G->handleUnsafeOperation(Handler,
false,
4447 assert(FixableGadgets.empty() &&
4448 "Fixable gadgets found but suggestions not requested!");
4454 if (!WarningGadgets.empty()) {
4458 for (
const auto &G : FixableGadgets) {
4459 for (
const auto *DRE : G->getClaimedVarUseSites()) {
4460 Tracker.claimUse(DRE);
4476 if (WarningGadgets.empty())
4484 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
4487 for (
auto it = FixablesForAllVars.
byVar.cbegin();
4488 it != FixablesForAllVars.
byVar.cend();) {
4493 (
"failed to produce fixit for '" +
4494 it->first->getNameAsString() +
4495 "' : neither local nor a parameter"));
4497 it = FixablesForAllVars.
byVar.erase(it);
4498 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
4501 (
"failed to produce fixit for '" +
4502 it->first->getNameAsString() +
4503 "' : has a reference type"));
4505 it = FixablesForAllVars.
byVar.erase(it);
4506 }
else if (Tracker.hasUnclaimedUses(it->first)) {
4507 it = FixablesForAllVars.
byVar.erase(it);
4508 }
else if (it->first->isInitCapture()) {
4511 (
"failed to produce fixit for '" +
4512 it->first->getNameAsString() +
4513 "' : init capture"));
4515 it = FixablesForAllVars.
byVar.erase(it);
4522 for (
const auto &it : UnsafeOps.
byVar) {
4523 const VarDecl *
const UnsafeVD = it.first;
4524 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
4525 if (UnclaimedDREs.empty())
4529 std::string UnclaimedUseTrace =
4534 (
"failed to produce fixit for '" + UnfixedVDName +
4535 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
4536 UnclaimedUseTrace));
4543 llvm::DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
4544 DepMapTy DependenciesMap{};
4545 DepMapTy PtrAssignmentGraph{};
4547 for (
const auto &it : FixablesForAllVars.
byVar) {
4548 for (
const FixableGadget *fixable : it.second) {
4549 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
4550 fixable->getStrategyImplications();
4552 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
4553 PtrAssignmentGraph[Impl.first].insert(Impl.second);
4575 std::set<const VarDecl *> VisitedVarsDirected{};
4576 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4577 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
4579 std::queue<const VarDecl *> QueueDirected{};
4580 QueueDirected.push(Var);
4581 while (!QueueDirected.empty()) {
4582 const VarDecl *CurrentVar = QueueDirected.front();
4583 QueueDirected.pop();
4584 VisitedVarsDirected.insert(CurrentVar);
4585 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
4586 for (
const VarDecl *Adj : AdjacentNodes) {
4587 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
4588 QueueDirected.push(Adj);
4590 DependenciesMap[Var].insert(Adj);
4591 DependenciesMap[Adj].insert(Var);
4598 std::vector<VarGrpTy> Groups;
4602 std::map<const VarDecl *, unsigned> VarGrpMap;
4604 llvm::SetVector<const VarDecl *>
4609 std::set<const VarDecl *> VisitedVars{};
4610 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4611 if (VisitedVars.find(Var) == VisitedVars.end()) {
4612 VarGrpTy &VarGroup = Groups.emplace_back();
4613 std::queue<const VarDecl *> Queue{};
4616 while (!Queue.empty()) {
4617 const VarDecl *CurrentVar = Queue.front();
4619 VisitedVars.insert(CurrentVar);
4620 VarGroup.push_back(CurrentVar);
4621 auto AdjacentNodes = DependenciesMap[CurrentVar];
4622 for (
const VarDecl *Adj : AdjacentNodes) {
4623 if (VisitedVars.find(Adj) == VisitedVars.end()) {
4629 bool HasParm =
false;
4630 unsigned GrpIdx = Groups.size() - 1;
4632 for (
const VarDecl *
V : VarGroup) {
4633 VarGrpMap[
V] = GrpIdx;
4638 GrpsUnionForParms.insert_range(VarGroup);
4660 for (
auto I = FixablesForAllVars.
byVar.begin();
4661 I != FixablesForAllVars.
byVar.end();) {
4663 if (!VisitedVars.count((*I).first)) {
4665 I = FixablesForAllVars.
byVar.erase(I);
4673 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
4675 return FixablesForAllVars.
byVar.count(
V);
4682 FixItsForVariableGroup =
4684 Tracker, Handler, VarGrpMgr);
4686 for (
const auto &G : UnsafeOps.
noVar) {
4687 G->handleUnsafeOperation(Handler,
false,
4691 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
4692 auto FixItsIt = FixItsForVariableGroup.find(VD);
4694 FixItsIt != FixItsForVariableGroup.end()
4695 ? std::move(FixItsIt->second)
4698 for (
const auto &G : WarningGadgets) {
4699 G->handleUnsafeOperation(Handler,
true,
4707 bool EmitSuggestions) {
4713 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
4721 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
4722 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
4727 if (FReDecl->isExternC()) {
4730 EmitSuggestions =
false;
4740 assert(!Stmts.empty());
4742 FixableGadgetList FixableGadgets;
4743 WarningGadgetList WarningGadgets;
4744 DeclUseTracker Tracker;
4745 for (
const Stmt *S : Stmts) {
4747 WarningGadgets, Tracker);
4749 applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
4750 std::move(Tracker), Handler, EmitSuggestions);
Defines the clang::ASTContext interface.
static Decl::Kind getKind(const Decl *D)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Preprocessor interface.
MatchFinder::MatchResult MatchResult
Defines the clang::SourceLocation class and associated facilities.
static QualType getPointeeType(const MemRegion *R)
C Language Family Type Representation.
static bool ignoreUnsafeLibcCall(const ASTContext &Ctx, const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
static void findStmtsInUnspecifiedLvalueContext(const Stmt *S, const llvm::function_ref< void(const Expr *)> OnResult)
static std::string getUserFillPlaceHolder(StringRef HintTextToUser="placeholder")
static FixItList fixVariableWithSpan(const VarDecl *VD, const DeclUseTracker &Tracker, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static std::optional< FixItList > fixUPCAddressofArraySubscriptWithSpan(const UnaryOperator *Node)
static bool ignoreUnsafeBufferInContainer(const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
static WarningGadgetSets groupWarningGadgetsByVar(const WarningGadgetList &AllUnsafeOperations)
static bool hasArrayType(const Expr &E)
static StringRef getEndOfLine()
static bool notInSafeBufferOptOut(const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
static std::optional< FixItList > FixVarInitializerWithSpan(const Expr *Init, ASTContext &Ctx, const StringRef UserFillPlaceHolder)
static std::optional< SourceLocation > getEndCharLoc(const NodeTy *Node, const SourceManager &SM, const LangOptions &LangOpts)
static FixItList fixVariableWithArray(const VarDecl *VD, const DeclUseTracker &Tracker, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static bool areEqualIntegralBinaryOperators(const BinaryOperator *E1, const Expr *E2_LHS, BinaryOperatorKind BOP, const Expr *E2_RHS, ASTContext &Ctx)
static bool hasPointerType(const Expr &E)
static std::string getSpanTypeText(StringRef EltTyText, std::optional< Qualifiers > Quals=std::nullopt)
static SourceRange getSourceRangeToTokenEnd(const Decl *D, const SourceManager &SM, const LangOptions &LangOpts)
static FixItList fixLocalVarDeclWithSpan(const VarDecl *D, ASTContext &Ctx, const StringRef UserFillPlaceHolder, UnsafeBufferUsageHandler &Handler)
static bool isSafeArraySubscript(const ArraySubscriptExpr &Node, const ASTContext &Ctx, const bool IgnoreStaticSizedArrays)
static std::optional< FixItList > createDataFixit(const ASTContext &Ctx, const DeclRefExpr *DRE)
static FixItList createFunctionOverloadsForParms(std::map< const VarDecl *, FixItList > &FixItsForVariable, const VariableGroupsManager &VarGrpMgr, const FunctionDecl *FD, const FixitStrategy &S, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static bool isNullTermPointer(const Expr *Ptr, ASTContext &Ctx)
static bool isSafeSpanTwoParamConstruct(const CXXConstructExpr &Node, ASTContext &Ctx)
static FixItList fixVarDeclWithArray(const VarDecl *D, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static FixItList fixVariable(const VarDecl *VD, FixitStrategy::Kind K, const Decl *D, const DeclUseTracker &Tracker, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static FixItList fixParamWithSpan(const ParmVarDecl *PVD, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static FixitStrategy getNaiveStrategy(llvm::iterator_range< VarDeclIterTy > UnsafeVars)
static std::optional< std::string > createSpanTypeForVarDecl(const VarDecl *VD, const ASTContext &Ctx)
static bool hasConflictingOverload(const FunctionDecl *FD)
static void findStmtsInUnspecifiedPointerContext(const Stmt *S, llvm::function_ref< void(const Stmt *)> InnerMatcher)
static bool isNonNegativeIntegerExpr(const Expr *Expr, const VarDecl *VD, const ASTContext &Ctx)
static bool overlapWithMacro(const FixItList &FixIts)
static void forEachDescendantStmt(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, FastMatcher &Matcher)
static bool hasUnsupportedSpecifiers(const VarDecl *VD, const SourceManager &SM)
static const Expr * tryConstantFoldConditionalExpr(const Expr *E, const ASTContext &Ctx)
#define DEBUG_NOTE_DECL_FAIL(D, Msg)
static void applyGadgets(const Decl *D, FixableGadgetList FixableGadgets, WarningGadgetList WarningGadgets, DeclUseTracker Tracker, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
static bool areEqualIntegers(const Expr *E1, const Expr *E2, ASTContext &Ctx)
static void findGadgets(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, bool EmitSuggestions, FixableGadgetList &FixableGadgets, WarningGadgetList &WarningGadgets, DeclUseTracker &Tracker)
static const Expr * getSubExprInSizeOfExpr(const Expr &E)
static std::map< const VarDecl *, FixItList > getFixIts(FixableGadgetSets &FixablesForAllVars, const FixitStrategy &S, ASTContext &Ctx, const Decl *D, const DeclUseTracker &Tracker, UnsafeBufferUsageHandler &Handler, const VariableGroupsManager &VarGrpMgr)
static bool isPtrBufferSafe(const Expr *Ptr, const Expr *Size, ASTContext &Ctx)
static const Expr * getSubExprInAddressOfExpr(const Expr &E)
static void forEachDescendantEvaluatedStmt(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, FastMatcher &Matcher)
static void findStmtsInUnspecifiedUntypedContext(const Stmt *S, llvm::function_ref< void(const Stmt *)> InnerMatcher)
static std::optional< FixItList > createOverloadsForFixedParams(const FixitStrategy &S, const FunctionDecl *FD, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static void eraseVarsForUnfixableGroupMates(std::map< const VarDecl *, FixItList > &FixItsForVariable, const VariableGroupsManager &VarGrpMgr)
static FixableGadgetSets groupFixablesByVar(FixableGadgetList &&AllFixableOperations)
static bool isParameterOf(const VarDecl *VD, const Decl *D)
#define SIZED_CONTAINER_OR_VIEW_LIST
static void populateStmtsForFindingGadgets(SmallVector< const Stmt * > &Stmts, const Decl *D)
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.
Expr * getInit() const
Get the initializer.
A use of a default initializer in a constructor or in aggregate initialization.
Expr * getExpr()
Get the initialization expression that will be used.
Represents a static or instance method of a struct/union/class.
Represents a C++11 noexcept expression (C++ [expr.unary.noexcept]).
OverloadedOperatorKind getOperator() const
Returns the kind of overloaded operator that this expression refers to.
Represents a C++ struct/union/class.
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
A C++ typeid expression (C++ [expr.typeid]), which gets the type_info that corresponds to the supplie...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
static const char * getCastKindName(CastKind CK)
Represents a byte-granular source range.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getEnd() const
bool isOne() const
isOne - Test whether the quantity equals one.
Represents a class template specialization, which refers to a class template with a given set of temp...
const TemplateArgumentList & getTemplateArgs() const
Retrieve the template arguments of the class template specialization.
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
bool isSingleResult() const
DeclContext * getParent()
getParent - Returns the containing DeclContext.
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
A reference to a declared variable, function, enum, etc.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
bool isSingleDecl() const
isSingleDecl - This method returns true if this DeclStmt refers to a single Decl.
const Decl * getSingleDecl() const
Decl - This represents one declaration (or definition), e.g.
bool isInStdNamespace() const
SourceLocation getEndLoc() const LLVM_READONLY
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
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.
ArrayRef< ParmVarDecl * > parameters() const
param_iterator param_begin()
bool isVariadic() const
Whether this function is variadic.
TemplatedKind getTemplatedKind() const
What kind of templated function this is.
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
bool isMain() const
Determines whether this function is "main", which is the entry point into an executable program.
bool isOverloadedOperator() const
Whether this function declaration represents an C++ overloaded operator, e.g., "operator+".
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
DeclarationNameInfo getNameInfo() const
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Represents a C11 generic selection.
Expr * getResultExpr()
Return the result expression of this controlling expression.
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
A simple pair of identifier info and location.
static IntegerLiteral * Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l)
Returns a new integer literal with value 'V' and type 'type'.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static std::optional< Token > findNextToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts, bool IncludeComments=false)
Finds the token that comes right after the given location.
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)
Computes the source location just past the end of the token at this source location.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
SourceLocation getBeginLoc() const
Retrieve the location of the beginning of this nested-name-specifier.
A single parameter index whose accessors require each use to make explicit the parameter index encodi...
bool isValid() const
Is this parameter index valid?
unsigned getASTIndex() const
Get the parameter index as it would normally be encoded at the AST level of representation: zero-orig...
Represents a parameter to a function.
bool hasDefaultArg() const
Determines whether this parameter has a default argument, either parsed or not.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
PointerType - C99 6.7.5.1 - Pointer Declarators.
A (possibly-)qualified type.
bool hasQualifiers() const
Determine whether this type has any qualifiers.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
QualType getCanonicalType() const
bool isConstQualified() const
Determine whether this type is const-qualified.
std::string getAsString() const
Represents a struct/union/class.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
Stmt - This represents one statement.
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const char * getStmtClassName() const
SourceLocation getBeginLoc() const LLVM_READONLY
Exposes information about the current target.
A template argument list.
unsigned size() const
Retrieve the number of template arguments in this template argument list.
Represents a template argument.
QualType getAsType() const
Retrieve the type for a type template argument.
@ Type
The template argument is a type.
ArgKind getKind() const
Return the kind of stored template argument.
The base class of the type hierarchy.
bool isConstantSizeType() const
Return true if this is not a variable sized type, according to the rules of C99 6....
bool isPointerType() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
const T * castAs() const
Member-template castAs<specific type>.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isAnyCharacterType() const
Determine whether this type is any of the built-in character types.
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
bool isAnyPointerType() const
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
static bool isIncrementOp(Opcode Op)
SourceLocation getBeginLoc() const LLVM_READONLY
static bool isDecrementOp(Opcode Op)
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
The interface that lets the caller handle unsafe buffer usage analysis results by overriding this cla...
virtual void handleUnsafeUniquePtrArrayAccess(const DynTypedNode &Node, bool IsRelatedToDecl, ASTContext &Ctx)=0
void addDebugNoteForVar(const VarDecl *VD, SourceLocation Loc, std::string Text)
virtual std::string getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, StringRef WSSuffix="") const =0
virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const =0
virtual bool ignoreUnsafeBufferInContainer(const SourceLocation &Loc) const =0
virtual void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation over raw pointers is found.
virtual void handleUnsafeVariableGroup(const VarDecl *Variable, const VariableGroupsManager &VarGrpMgr, FixItList &&Fixes, const Decl *D, const FixitStrategy &VarTargetTypes)=0
Invoked when a fix is suggested against a variable.
virtual void handleUnsafeOperationInContainer(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation with a std container is found.
virtual bool ignoreUnsafeBufferInStaticSizedArray(const SourceLocation &Loc) const =0
virtual bool ignoreUnsafeBufferInLibcCall(const SourceLocation &Loc) const =0
virtual void handleUnsafeLibcCall(const CallExpr *Call, unsigned PrintfInfo, ASTContext &Ctx, const Expr *UnsafeArg=nullptr)=0
Invoked when a call to an unsafe libc function is found.
Represents a variable declaration or definition.
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
VarDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
bool isInlineSpecified() const
bool hasConstantInitialization() const
Determine whether this variable has constant initialization.
const Expr * getInit() const
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
const Expr * getAnyInitializer() const
Get the initializer for this variable, no matter which declaration it is attached to.
VariableGroupsManager()=default
virtual VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm=nullptr) const =0
Returns the set of variables (including Var) that need to be fixed together in one step.
virtual VarGrpRef getGroupOfParms() const =0
Returns the non-empty group of variables that include parameters of the analyzing function,...
unsigned getArgIndex() const
bool hasDataArgument() const
HowSpecified getHowSpecified() const
unsigned getConstantAmount() const
const OptionalAmount & getPrecision() const
const PrintfConversionSpecifier & getConversionSpecifier() const
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
void matchEachArgumentWithParamType(const CallExpr &Node, llvm::function_ref< void(QualType, const Expr *)> OnParamAndArg)
bool anyConflict(const llvm::SmallVectorImpl< FixItHint > &FixIts, const SourceManager &SM)
bool matches(const til::SExpr *E1, const til::SExpr *E2)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
SourceLocation getVarDeclIdentifierLoc(const DeclaratorDecl *VD)
static bool classof(const OMPClause *T)
std::vector< const VarDecl * > VarGrpTy
std::optional< StringRef > getExprText(const Expr *E, const SourceManager &SM, const LangOptions &LangOpts)
@ Result
The result type of a method or function.
std::optional< std::string > getPointeeTypeText(const DeclaratorDecl *VD, const SourceManager &SM, const LangOptions &LangOpts, std::optional< Qualifiers > *QualifiersToAppend)
std::optional< StringRef > getRangeText(SourceRange SR, const SourceManager &SM, const LangOptions &LangOpts)
std::optional< StringRef > getVarDeclIdentifierText(const DeclaratorDecl *VD, const SourceManager &SM, const LangOptions &LangOpts)
std::optional< SourceLocation > getPastLoc(const NodeTy *Node, const SourceManager &SM, const LangOptions &LangOpts)
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
ArrayRef< const VarDecl * > VarGrpRef
std::set< const Expr * > findUnsafePointers(const Decl *D)
Find unsafe pointers in body/initializer of D, if D is one of the followings: VarDecl FieldDecl Funct...
static StringRef matchLibcNameOrBuiltinChk(StringRef Name)
static bool hasUnsafePrintfStringArg(const CallExpr &Node, ASTContext &Ctx, MatchResult &Result, llvm::StringRef Tag)
static bool isPredefinedUnsafeLibcFunc(const FunctionDecl &Node)
static bool hasUnsafeSnprintfBuffer(const CallExpr &Node, ASTContext &Ctx)
static bool isUnsafeVaListPrintfFunc(const FunctionDecl &Node)
static bool isUnsafeSprintfFunc(const FunctionDecl &Node)
static bool hasUnsafeFormatOrSArg(ASTContext &Ctx, const CallExpr *Call, const Expr *&UnsafeArg, const unsigned FmtIdx, std::optional< const unsigned > FmtArgIdx=std::nullopt, bool isKprintf=false)
static StringRef matchLibcName(StringRef Name)
static bool isUnsafeMemset(const CallExpr &Node, ASTContext &Ctx)
static StringRef matchName(StringRef FunName, bool isBuiltin)
static bool isNormalPrintfFunc(const FunctionDecl &Node)
bool operator()(const NodeTy *N1, const NodeTy *N2) const
std::map< const VarDecl *, std::set< const FixableGadget * >, CompareNode< VarDecl > > byVar
std::map< const VarDecl *, std::set< const WarningGadget * >, CompareNode< VarDecl > > byVar
llvm::SmallVector< const WarningGadget *, 16 > noVar
SourceLocation getBeginLoc() const
getBeginLoc - Retrieve the location of the first token.
SourceLocation getEndLoc() const LLVM_READONLY
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.
const BoundNodes Nodes
Contains the nodes bound on the current match.