29#include "llvm/ADT/APInt.h"
30#include "llvm/ADT/APSInt.h"
31#include "llvm/ADT/STLFunctionalExtras.h"
32#include "llvm/ADT/SmallSet.h"
33#include "llvm/ADT/SmallVector.h"
34#include "llvm/ADT/StringRef.h"
50 std::string VisitBinaryOperator(
const BinaryOperator *BO) {
51 return "BinaryOperator(" + BO->
getOpcodeStr().str() +
")";
54 std::string VisitUnaryOperator(
const UnaryOperator *UO) {
58 std::string VisitImplicitCastExpr(
const ImplicitCastExpr *ICE) {
65static std::string getDREAncestorString(
const DeclRefExpr *DRE,
69 StmtDebugPrinter StmtPriner;
72 SS << StmtPriner.Visit(St);
76 if (StParents.
size() > 1)
77 return "unavailable due to multiple parents";
78 if (StParents.
empty())
97 virtual bool matches(
const DynTypedNode &DynNode, ASTContext &Ctx,
98 const UnsafeBufferUsageHandler &Handler) = 0;
99 virtual ~FastMatcher() =
default;
105 template <
typename T>
const T *getNodeAs(StringRef ID)
const {
106 auto It =
Nodes.find(ID);
107 if (It ==
Nodes.end()) {
110 return It->second.get<
T>();
113 void addNode(StringRef ID,
const DynTypedNode &Node) {
Nodes[
ID] = Node; }
116 llvm::StringMap<DynTypedNode>
Nodes;
120#define SIZED_CONTAINER_OR_VIEW_LIST \
121 "span", "array", "vector", "basic_string_view", "basic_string", \
132 bool FindAll,
bool ignoreUnevaluatedContext,
134 : Matcher(&Matcher), FindAll(FindAll), Matches(
false),
135 ignoreUnevaluatedContext(ignoreUnevaluatedContext),
136 ActiveASTContext(&Context), Handler(&NewHandler) {
173 if (ignoreUnevaluatedContext)
175 return DynamicRecursiveASTVisitor::TraverseGenericSelectionExpr(Node);
181 if (ignoreUnevaluatedContext)
183 return DynamicRecursiveASTVisitor::TraverseUnaryExprOrTypeTraitExpr(Node);
187 bool TraverseQualifier)
override {
189 if (ignoreUnevaluatedContext)
191 return DynamicRecursiveASTVisitor::TraverseTypeOfExprTypeLoc(
192 Node, TraverseQualifier);
196 bool TraverseQualifier)
override {
198 if (ignoreUnevaluatedContext)
200 return DynamicRecursiveASTVisitor::TraverseDecltypeTypeLoc(
201 Node, TraverseQualifier);
206 if (ignoreUnevaluatedContext)
208 return DynamicRecursiveASTVisitor::TraverseCXXNoexceptExpr(Node);
213 if (ignoreUnevaluatedContext)
215 return DynamicRecursiveASTVisitor::TraverseCXXTypeidExpr(Node);
221 return DynamicRecursiveASTVisitor::TraverseCXXDefaultInitExpr(Node);
237 template <
typename T>
bool match(
const T &Node) {
247 FastMatcher *
const Matcher;
251 bool ignoreUnevaluatedContext;
252 ASTContext *ActiveASTContext;
253 const UnsafeBufferUsageHandler *Handler;
268 FastMatcher &Matcher) {
276 FastMatcher &Matcher) {
304 const Stmt *S,
const llvm::function_ref<
void(
const Expr *)> OnResult) {
305 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(S);
306 CE && CE->getCastKind() == CastKind::CK_LValueToRValue)
307 OnResult(CE->getSubExpr());
308 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
316 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
325 if (
auto *CE = dyn_cast<CallExpr>(S)) {
326 if (
const auto *FnDecl = CE->getDirectCallee();
327 FnDecl && FnDecl->hasAttr<UnsafeBufferUsageAttr>())
336 if (
auto *CE = dyn_cast<CastExpr>(S)) {
337 if (CE->getCastKind() != CastKind::CK_PointerToIntegral &&
338 CE->getCastKind() != CastKind::CK_PointerToBoolean)
342 InnerMatcher(CE->getSubExpr());
346 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
360 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
366 InnerMatcher(BO->
getLHS());
367 InnerMatcher(BO->
getRHS());
385 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
390 if (
auto *CS = dyn_cast<CompoundStmt>(S)) {
391 for (
auto *Child : CS->body())
394 if (
auto *IfS = dyn_cast<IfStmt>(S)) {
396 InnerMatcher(IfS->getThen());
398 InnerMatcher(IfS->getElse());
449 case Stmt::DeclRefExprClass:
451 case Stmt::BinaryOperatorClass: {
454 BO2->getLHS(), BO2->getOpcode(),
480 dyn_cast<CXXMemberCallExpr>(Size->IgnoreParenImpCasts())) {
481 auto *DREOfPtr = dyn_cast<DeclRefExpr>(
482 MCEPtr->getImplicitObjectArgument()->IgnoreParenImpCasts());
483 auto *DREOfSize = dyn_cast<DeclRefExpr>(
484 MCESize->getImplicitObjectArgument()->IgnoreParenImpCasts());
486 if (!DREOfPtr || !DREOfSize)
490 if (DREOfPtr->getDecl() != DREOfSize->getDecl())
492 if (MCEPtr->getMethodDecl()->getName() !=
"data")
495 if (!MCEPtr->getRecordDecl()->isInStdNamespace())
498 auto *ObjII = MCEPtr->getRecordDecl()->getIdentifier();
505 if (!((AcceptSizeBytes &&
506 MCESize->getMethodDecl()->getName() ==
"size_bytes") ||
511 MCESize->getMethodDecl()->getName() ==
"size"))
521 if (Size->EvaluateAsInt(ER, Ctx)) {
527 return llvm::APSInt::compareValues(
528 SizeInt, llvm::APSInt(CAT->getSize(),
true)) == 0;
536 return UO && UO->
getOpcode() == UnaryOperator::Opcode::UO_AddrOf;
538 auto *FnDecl = CE->getDirectCallee();
540 return FnDecl && FnDecl->getNameAsString() ==
"addressof" &&
541 FnDecl->isInStdNamespace();
569 "expecting a two-parameter std::span constructor");
572 auto HaveEqualConstantValues = [&Ctx](
const Expr *E0,
const Expr *E1) {
574 if (
auto E1CV = E1->getIntegerConstantExpr(Ctx)) {
575 return llvm::APSInt::compareValues(*E0CV, *E1CV) == 0;
579 auto AreSameDRE = [](
const Expr *E0,
const Expr *E1) {
580 if (
auto *DRE0 = dyn_cast<DeclRefExpr>(E0))
581 if (
auto *DRE1 = dyn_cast<DeclRefExpr>(E1)) {
582 return DRE0->getDecl() == DRE1->getDecl();
588 if (Arg1CV && Arg1CV->isZero())
594 case Stmt::CXXNewExprClass:
597 return AreSameDRE((*Size)->IgnoreImplicit(), Arg1) ||
598 HaveEqualConstantValues(*Size, Arg1);
603 return Arg1CV && Arg1CV->isOne();
611 if (
auto CCast = dyn_cast<CStyleCastExpr>(Arg0)) {
612 if (!CCast->getType()->isPointerType())
620 if (
const auto *
Call = dyn_cast<CallExpr>(CCast->getSubExpr())) {
622 if (
auto *AllocAttr = FD->getAttr<AllocSizeAttr>()) {
623 const Expr *EleSizeExpr =
624 Call->getArg(AllocAttr->getElemSizeParam().getASTIndex());
626 ParamIdx NumElemIdx = AllocAttr->getNumElemsParam();
633 if (
auto BO = dyn_cast<BinaryOperator>(Arg1))
640 auto IsMethodCallToSizedObject = [](
const Stmt *Node, StringRef MethodName) {
641 if (
const auto *MC = dyn_cast<CXXMemberCallExpr>(Node)) {
642 const auto *MD = MC->getMethodDecl();
643 const auto *RD = MC->getRecordDecl();
646 if (
auto *II = RD->getDeclName().getAsIdentifierInfo();
647 II && RD->isInStdNamespace())
650 MD->getName() == MethodName;
655 if (IsMethodCallToSizedObject(Arg0,
"begin") &&
656 IsMethodCallToSizedObject(Arg1,
"end"))
660 ->getImplicitObjectArgument()
661 ->IgnoreParenImpCasts(),
663 ->getImplicitObjectArgument()
664 ->IgnoreParenImpCasts());
680 if (
const auto *CATy =
681 dyn_cast<ConstantArrayType>(Node.
getBase()
685 limit = CATy->getLimitedSize();
686 }
else if (
const auto *SLiteral = dyn_cast<clang::StringLiteral>(
688 limit = SLiteral->getLength() + 1;
697 llvm::APSInt ArrIdx = EVResult.
Val.
getInt();
700 if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit)
702 }
else if (
const auto *BE = dyn_cast<BinaryOperator>(IndexExpr)) {
705 if (BE->getOpcode() != BO_And && BE->getOpcode() != BO_Rem)
708 const Expr *LHS = BE->getLHS();
709 const Expr *RHS = BE->getRHS();
711 if (BE->getOpcode() == BO_Rem) {
718 llvm::APSInt result = EVResult.
Val.
getInt();
719 if (result.isNonNegative() && result.getLimitedValue() <= limit)
730 llvm::APSInt result = EVResult.
Val.
getInt();
731 if (result.isNonNegative() && result.getLimitedValue() < limit)
745 if (
const auto *CE = dyn_cast<ConditionalOperator>(E)) {
747 const auto *
Cond = CE->getCond();
749 if (!
Cond->isValueDependent() &&
750 Cond->EvaluateAsBooleanCondition(CondEval, Ctx))
751 return CondEval ? CE->getLHS() : CE->getRHS();
791 StringRef
matchName(StringRef FunName,
bool isBuiltin) {
793 if (isBuiltin && FunName.starts_with(
"__builtin_"))
797 FunName.drop_front(10 ));
799 if (FunName.starts_with(
"__asan_"))
807 if (Name.starts_with(
"__") && Name.ends_with(
"_chk"))
809 Name.drop_front(2).drop_back(4) );
814 if (Name.ends_with(
"_s"))
815 return Name.drop_back(2 );
830 bool isKprintf =
false) {
831 class StringFormatStringHandler
835 const Expr *&UnsafeArg;
849 unsigned PArgIdx = -1;
853 if (0 < PArgIdx && PArgIdx < Call->getNumArgs()) {
854 const Expr *PArg =
Call->getArg(PArgIdx);
857 if (
auto *CE = dyn_cast<CastExpr>(PArg);
858 CE && CE->getType()->isSignedIntegerType())
859 PArg = CE->getSubExpr();
863 analyze_printf::OptionalAmount::HowSpecified::Constant) {
865 llvm::APSInt PArgVal = llvm::APSInt(
875 StringFormatStringHandler(
const CallExpr *
Call,
unsigned FmtArgIdx,
877 :
Call(
Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx) {}
880 const char *startSpecifier,
881 unsigned specifierLen,
889 if (!(0 < ArgIdx && ArgIdx < Call->getNumArgs()))
893 const Expr *Arg =
Call->getArg(ArgIdx);
903 bool IsArgTypeValid =
906 ?
ArgType->getPointeeType()->isWideCharType()
907 :
ArgType->getPointeeType()->isCharType());
910 Precision && IsArgTypeValid)
914 UnsafeArg =
Call->getArg(ArgIdx);
919 const Expr *Fmt =
Call->getArg(FmtArgIdx);
922 if (SL->getCharByteWidth() == 1) {
923 StringRef FmtStr = SL->getString();
924 StringFormatStringHandler Handler(
Call, FmtArgIdx, UnsafeArg, Ctx);
927 Handler, FmtStr.begin(), FmtStr.end(), Ctx.
getLangOpts(),
931 if (
auto FmtStr = SL->tryEvaluateString(Ctx)) {
932 StringFormatStringHandler Handler(
Call, FmtArgIdx, UnsafeArg, Ctx);
934 Handler, FmtStr->data(), FmtStr->data() + FmtStr->size(),
942 llvm::make_range(
Call->arg_begin() + FmtArgIdx,
Call->arg_end()),
943 [&UnsafeArg, &Ctx](
const Expr *Arg) ->
bool {
944 if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg, Ctx)) {
962 static std::unique_ptr<std::set<StringRef>> PredefinedNames =
nullptr;
963 if (!PredefinedNames)
965 std::make_unique<std::set<StringRef>, std::set<StringRef>>({
1046 if (PredefinedNames->find(Name) != PredefinedNames->end())
1049 std::string NameWCS = Name.str();
1050 size_t WcsPos = NameWCS.find(
"wcs");
1052 while (WcsPos != std::string::npos) {
1053 NameWCS[WcsPos++] =
's';
1054 NameWCS[WcsPos++] =
't';
1055 NameWCS[WcsPos++] =
'r';
1056 WcsPos = NameWCS.find(
"wcs", WcsPos);
1058 if (PredefinedNames->find(NameWCS) != PredefinedNames->end())
1062 return Name.ends_with(
"scanf");
1077 if (!Name.ends_with(
"printf"))
1079 return Name.starts_with(
"v");
1093 if (!Name.ends_with(
"printf") ||
1095 Name.starts_with(
"v"))
1098 StringRef Prefix = Name.drop_back(6);
1100 if (Prefix.ends_with(
"w"))
1101 Prefix = Prefix.drop_back(1);
1102 return Prefix ==
"s";
1117 if (!Name.ends_with(
"printf") || Name.starts_with(
"v"))
1120 StringRef Prefix = Name.drop_back(6);
1122 if (Prefix.ends_with(
"w"))
1123 Prefix = Prefix.drop_back(1);
1125 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
1133 MatchResult &Result, llvm::StringRef Tag) {
1137 assert(FD &&
"It should have been checked that FD is non-null.");
1155 const Expr *UnsafeArg;
1166 bool isKprintf =
false;
1167 const Expr *UnsafeArg;
1170 isKprintf = II->getName() ==
"kprintf";
1184 const Expr *UnsafeArg;
1195 for (
const auto *Arg : Node.
arguments())
1210 assert(FD &&
"It should have been checked that FD is non-null.");
1225 !Size->getType()->isUnsignedIntegerType())
1254#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1257 Gadget(Kind K) : K(K) {}
1259 Kind
getKind()
const {
return K; }
1262 StringRef getDebugName()
const {
1267#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1269 llvm_unreachable(
"Unhandled Gadget::Kind enum");
1273 virtual bool isWarningGadget()
const = 0;
1276 virtual SourceLocation getSourceLoc()
const = 0;
1281 virtual DeclUseList getClaimedVarUseSites()
const = 0;
1283 virtual ~Gadget() =
default;
1291class WarningGadget :
public Gadget {
1293 WarningGadget(Kind K) : Gadget(K) {}
1295 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1296 bool isWarningGadget() const final {
return true; }
1298 virtual void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1299 bool IsRelatedToDecl,
1300 ASTContext &Ctx)
const = 0;
1302 virtual SmallVector<const Expr *, 1> getUnsafePtrs()
const = 0;
1309class FixableGadget :
public Gadget {
1311 FixableGadget(Kind K) : Gadget(K) {}
1313 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1314 bool isWarningGadget() const final {
return false; }
1319 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1320 return std::nullopt;
1329 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1330 getStrategyImplications()
const {
1331 return std::nullopt;
1335static bool isSupportedVariable(
const DeclRefExpr &Node) {
1347 dyn_cast<ClassTemplateSpecializationDecl>(
RecordDecl);
1348 if (!class_template_specialization_decl)
1353 if (template_args.
size() == 0)
1364class UniquePtrArrayAccessGadget :
public WarningGadget {
1366 static constexpr const char *
const AccessorTag =
"unique_ptr_array_access";
1367 const CXXOperatorCallExpr *AccessorExpr;
1371 : WarningGadget(
Kind::UniquePtrArrayAccess),
1372 AccessorExpr(
Result.getNodeAs<CXXOperatorCallExpr>(AccessorTag)) {
1373 assert(AccessorExpr &&
1374 "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr");
1377 static bool classof(
const Gadget *G) {
1378 return G->getKind() == Kind::UniquePtrArrayAccess;
1381 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1384 const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(S);
1385 if (!OpCall || OpCall->
getOperator() != OO_Subscript)
1392 const CXXMethodDecl *
Method =
1397 if (
Method->getOverloadedOperator() != OO_Subscript)
1401 if (!isUniquePtrArray(RecordDecl))
1404 const Expr *IndexExpr = OpCall->
getArg(1);
1405 clang::Expr::EvalResult Eval;
1411 Result.addNode(AccessorTag, DynTypedNode::create(*OpCall));
1414 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1415 bool IsRelatedToDecl,
1416 ASTContext &Ctx)
const override {
1418 DynTypedNode::create(*AccessorExpr), IsRelatedToDecl, Ctx);
1421 SourceLocation getSourceLoc()
const override {
1423 return AccessorExpr->getOperatorLoc();
1424 return SourceLocation();
1427 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1428 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1431using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1432using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1436class IncrementGadget :
public WarningGadget {
1437 static constexpr const char *
const OpTag =
"op";
1438 const UnaryOperator *Op;
1442 : WarningGadget(
Kind::Increment),
1443 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1445 static bool classof(
const Gadget *G) {
1446 return G->getKind() == Kind::Increment;
1449 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1451 const auto *UO = dyn_cast<UnaryOperator>(S);
1456 Result.addNode(OpTag, DynTypedNode::create(*UO));
1460 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1461 bool IsRelatedToDecl,
1462 ASTContext &Ctx)
const override {
1465 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1467 DeclUseList getClaimedVarUseSites()
const override {
1468 SmallVector<const DeclRefExpr *, 2> Uses;
1469 if (
const auto *DRE =
1470 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1471 Uses.push_back(DRE);
1474 return std::move(Uses);
1477 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1478 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1484class DecrementGadget :
public WarningGadget {
1485 static constexpr const char *
const OpTag =
"op";
1486 const UnaryOperator *Op;
1490 : WarningGadget(
Kind::Decrement),
1491 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1493 static bool classof(
const Gadget *G) {
1494 return G->getKind() == Kind::Decrement;
1497 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1499 const auto *UO = dyn_cast<UnaryOperator>(S);
1504 Result.addNode(OpTag, DynTypedNode::create(*UO));
1508 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1509 bool IsRelatedToDecl,
1510 ASTContext &Ctx)
const override {
1513 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1515 DeclUseList getClaimedVarUseSites()
const override {
1516 if (
const auto *DRE =
1517 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1524 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1525 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1531class ArraySubscriptGadget :
public WarningGadget {
1532 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1533 const ArraySubscriptExpr *ASE;
1538 ASE(
Result.getNodeAs<ArraySubscriptExpr>(ArraySubscrTag)) {}
1540 static bool classof(
const Gadget *G) {
1541 return G->getKind() == Kind::ArraySubscript;
1544 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1546 const auto *ASE = dyn_cast<ArraySubscriptExpr>(S);
1549 const auto *
const Base = ASE->getBase()->IgnoreParenImpCasts();
1552 const auto *Idx = dyn_cast<IntegerLiteral>(ASE->getIdx());
1553 bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
1557 Result.addNode(ArraySubscrTag, DynTypedNode::create(*ASE));
1561 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1562 bool IsRelatedToDecl,
1563 ASTContext &Ctx)
const override {
1566 SourceLocation getSourceLoc()
const override {
return ASE->getBeginLoc(); }
1568 DeclUseList getClaimedVarUseSites()
const override {
1569 if (
const auto *DRE =
1570 dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
1577 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1578 return {ASE->getBase()->IgnoreParenImpCasts()};
1586class PointerArithmeticGadget :
public WarningGadget {
1587 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1588 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1589 const BinaryOperator *PA;
1594 : WarningGadget(
Kind::PointerArithmetic),
1595 PA(
Result.getNodeAs<BinaryOperator>(PointerArithmeticTag)),
1596 Ptr(
Result.getNodeAs<Expr>(PointerArithmeticPointerTag)) {}
1598 static bool classof(
const Gadget *G) {
1599 return G->getKind() == Kind::PointerArithmetic;
1602 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1604 const auto *BO = dyn_cast<BinaryOperator>(S);
1607 const auto *LHS = BO->
getLHS();
1608 const auto *RHS = BO->
getRHS();
1613 RHS->getType()->isEnumeralType())) {
1614 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*LHS));
1615 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1621 (LHS->getType()->isIntegerType() || LHS->getType()->isEnumeralType())) {
1622 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*RHS));
1623 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1629 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1630 bool IsRelatedToDecl,
1631 ASTContext &Ctx)
const override {
1634 SourceLocation getSourceLoc()
const override {
return PA->getBeginLoc(); }
1636 DeclUseList getClaimedVarUseSites()
const override {
1637 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts())) {
1644 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1645 return {Ptr->IgnoreParenImpCasts()};
1652class SpanTwoParamConstructorGadget :
public WarningGadget {
1653 static constexpr const char *
const SpanTwoParamConstructorTag =
1654 "spanTwoParamConstructor";
1655 const CXXConstructExpr *Ctor;
1659 : WarningGadget(
Kind::SpanTwoParamConstructor),
1660 Ctor(
Result.getNodeAs<CXXConstructExpr>(SpanTwoParamConstructorTag)) {}
1662 static bool classof(
const Gadget *G) {
1663 return G->getKind() == Kind::SpanTwoParamConstructor;
1667 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1670 const auto *CDecl = CE->getConstructor();
1671 const auto *CRecordDecl = CDecl->getParent();
1672 auto HasTwoParamSpanCtorDecl =
1673 CRecordDecl->isInStdNamespace() &&
1674 CDecl->getDeclName().getAsString() ==
"span" && CE->getNumArgs() == 2;
1677 Result.addNode(SpanTwoParamConstructorTag, DynTypedNode::create(*CE));
1681 static bool matches(
const Stmt *S, ASTContext &Ctx,
1682 const UnsafeBufferUsageHandler *Handler,
1689 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1690 bool IsRelatedToDecl,
1691 ASTContext &Ctx)
const override {
1694 SourceLocation getSourceLoc()
const override {
return Ctor->getBeginLoc(); }
1696 DeclUseList getClaimedVarUseSites()
const override {
1699 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->getArg(0))) {
1706 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1713class PointerInitGadget :
public FixableGadget {
1715 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1716 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1717 const VarDecl *PtrInitLHS;
1718 const DeclRefExpr *PtrInitRHS;
1722 : FixableGadget(
Kind::PointerInit),
1723 PtrInitLHS(
Result.getNodeAs<VarDecl>(PointerInitLHSTag)),
1724 PtrInitRHS(
Result.getNodeAs<DeclRefExpr>(PointerInitRHSTag)) {}
1726 static bool classof(
const Gadget *G) {
1727 return G->getKind() == Kind::PointerInit;
1730 static bool matches(
const Stmt *S,
1731 llvm::SmallVectorImpl<MatchResult> &Results) {
1732 const DeclStmt *DS = dyn_cast<DeclStmt>(S);
1741 const auto *DRE = dyn_cast<DeclRefExpr>(
Init->IgnoreImpCasts());
1742 if (!DRE || !
hasPointerType(*DRE) || !isSupportedVariable(*DRE)) {
1746 R.addNode(PointerInitLHSTag, DynTypedNode::create(*VD));
1747 R.addNode(PointerInitRHSTag, DynTypedNode::create(*DRE));
1748 Results.emplace_back(std::move(R));
1752 virtual std::optional<FixItList>
1753 getFixits(
const FixitStrategy &S)
const override;
1754 SourceLocation getSourceLoc()
const override {
1755 return PtrInitRHS->getBeginLoc();
1758 virtual DeclUseList getClaimedVarUseSites()
const override {
1759 return DeclUseList{PtrInitRHS};
1762 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1763 getStrategyImplications()
const override {
1764 return std::make_pair(PtrInitLHS,
cast<VarDecl>(PtrInitRHS->getDecl()));
1773class PtrToPtrAssignmentGadget :
public FixableGadget {
1775 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1776 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1777 const DeclRefExpr *PtrLHS;
1778 const DeclRefExpr *PtrRHS;
1782 : FixableGadget(
Kind::PtrToPtrAssignment),
1783 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1784 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1786 static bool classof(
const Gadget *G) {
1787 return G->getKind() == Kind::PtrToPtrAssignment;
1790 static bool matches(
const Stmt *S,
1791 llvm::SmallVectorImpl<MatchResult> &Results) {
1792 size_t SizeBefore = Results.size();
1794 const auto *BO = dyn_cast<BinaryOperator>(S);
1795 if (!BO || BO->
getOpcode() != BO_Assign)
1798 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1800 !isSupportedVariable(*RHSRef)) {
1803 const auto *LHS = BO->
getLHS();
1804 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1806 !isSupportedVariable(*LHSRef)) {
1810 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1811 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1812 Results.emplace_back(std::move(R));
1814 return SizeBefore != Results.size();
1817 virtual std::optional<FixItList>
1818 getFixits(
const FixitStrategy &S)
const override;
1819 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1821 virtual DeclUseList getClaimedVarUseSites()
const override {
1822 return DeclUseList{PtrLHS, PtrRHS};
1825 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1826 getStrategyImplications()
const override {
1837class CArrayToPtrAssignmentGadget :
public FixableGadget {
1839 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1840 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1841 const DeclRefExpr *PtrLHS;
1842 const DeclRefExpr *PtrRHS;
1846 : FixableGadget(
Kind::CArrayToPtrAssignment),
1847 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1848 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1850 static bool classof(
const Gadget *G) {
1851 return G->getKind() == Kind::CArrayToPtrAssignment;
1854 static bool matches(
const Stmt *S,
1855 llvm::SmallVectorImpl<MatchResult> &Results) {
1856 size_t SizeBefore = Results.size();
1858 const auto *BO = dyn_cast<BinaryOperator>(S);
1859 if (!BO || BO->
getOpcode() != BO_Assign)
1862 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1865 !isSupportedVariable(*RHSRef)) {
1868 const auto *LHS = BO->
getLHS();
1869 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1871 !isSupportedVariable(*LHSRef)) {
1875 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1876 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1877 Results.emplace_back(std::move(R));
1879 return SizeBefore != Results.size();
1882 virtual std::optional<FixItList>
1883 getFixits(
const FixitStrategy &S)
const override;
1884 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1886 virtual DeclUseList getClaimedVarUseSites()
const override {
1887 return DeclUseList{PtrLHS, PtrRHS};
1890 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1891 getStrategyImplications()
const override {
1898class UnsafeBufferUsageAttrGadget :
public WarningGadget {
1899 constexpr static const char *
const OpTag =
"attr_expr";
1904 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
1905 Op(
Result.getNodeAs<Expr>(OpTag)) {}
1907 static bool classof(
const Gadget *G) {
1908 return G->getKind() == Kind::UnsafeBufferUsageAttr;
1911 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1913 if (
auto *CE = dyn_cast<CallExpr>(S)) {
1914 if (CE->getDirectCallee() &&
1915 CE->getDirectCallee()->hasAttr<UnsafeBufferUsageAttr>()) {
1916 Result.addNode(OpTag, DynTypedNode::create(*CE));
1920 if (
auto *ME = dyn_cast<MemberExpr>(S)) {
1923 if (ME->getMemberDecl()->hasAttr<UnsafeBufferUsageAttr>()) {
1924 Result.addNode(OpTag, DynTypedNode::create(*ME));
1931 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1932 bool IsRelatedToDecl,
1933 ASTContext &Ctx)
const override {
1936 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1938 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1940 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1946class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
1947 constexpr static const char *
const OpTag =
"cxx_construct_expr";
1948 const CXXConstructExpr *Op;
1952 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
1953 Op(
Result.getNodeAs<CXXConstructExpr>(OpTag)) {}
1955 static bool classof(
const Gadget *G) {
1956 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
1960 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1961 if (!CE || !CE->getConstructor()->hasAttr<UnsafeBufferUsageAttr>())
1965 if (SpanTwoParamConstructorGadget::matches(CE, Ctx, Tmp))
1967 Result.addNode(OpTag, DynTypedNode::create(*CE));
1971 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1972 bool IsRelatedToDecl,
1973 ASTContext &Ctx)
const override {
1976 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1978 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1980 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1987class DataInvocationGadget :
public WarningGadget {
1988 constexpr static const char *
const OpTag =
"data_invocation_expr";
1989 const ExplicitCastExpr *Op;
1993 : WarningGadget(
Kind::DataInvocation),
1994 Op(
Result.getNodeAs<ExplicitCastExpr>(OpTag)) {}
1996 static bool classof(
const Gadget *G) {
1997 return G->getKind() == Kind::DataInvocation;
2000 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2002 auto *CE = dyn_cast<ExplicitCastExpr>(S);
2005 for (
auto *Child : CE->children()) {
2006 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Child);
2007 MCE && isDataFunction(MCE)) {
2008 Result.addNode(OpTag, DynTypedNode::create(*CE));
2011 if (
auto *
Paren = dyn_cast<ParenExpr>(Child)) {
2012 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(
Paren->getSubExpr());
2013 MCE && isDataFunction(MCE)) {
2014 Result.addNode(OpTag, DynTypedNode::create(*CE));
2022 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2023 bool IsRelatedToDecl,
2024 ASTContext &Ctx)
const override {
2027 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2029 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2032 static bool isDataFunction(
const CXXMemberCallExpr *call) {
2039 if (method->getNameAsString() ==
"data" &&
2040 method->getParent()->isInStdNamespace() &&
2041 llvm::is_contained({SIZED_CONTAINER_OR_VIEW_LIST},
2042 method->getParent()->getName()))
2047 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2050class UnsafeLibcFunctionCallGadget :
public WarningGadget {
2051 const CallExpr *
const Call;
2052 const Expr *UnsafeArg =
nullptr;
2053 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
2055 constexpr static const char *
const UnsafeSprintfTag =
2056 "UnsafeLibcFunctionCall_sprintf";
2057 constexpr static const char *
const UnsafeSizedByTag =
2058 "UnsafeLibcFunctionCall_sized_by";
2059 constexpr static const char *
const UnsafeStringTag =
2060 "UnsafeLibcFunctionCall_string";
2061 constexpr static const char *
const UnsafeVaListTag =
2062 "UnsafeLibcFunctionCall_va_list";
2074 } WarnedFunKind = OTHERS;
2078 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2079 Call(
Result.getNodeAs<CallExpr>(Tag)) {
2080 if (
Result.getNodeAs<Decl>(UnsafeSprintfTag))
2081 WarnedFunKind = SPRINTF;
2082 else if (
auto *E =
Result.getNodeAs<Expr>(UnsafeStringTag)) {
2083 WarnedFunKind = STRING;
2085 }
else if (
Result.getNodeAs<CallExpr>(UnsafeSizedByTag)) {
2086 WarnedFunKind = SIZED_BY;
2087 UnsafeArg = Call->getArg(0);
2088 }
else if (
Result.getNodeAs<Decl>(UnsafeVaListTag))
2089 WarnedFunKind = VA_LIST;
2092 static bool matches(
const Stmt *S, ASTContext &Ctx,
2093 const UnsafeBufferUsageHandler *Handler,
2097 auto *CE = dyn_cast<CallExpr>(S);
2098 if (!CE || !CE->getDirectCallee())
2100 const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
2104 bool IsGlobalAndNotInAnyNamespace =
2105 FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
2109 if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
2115 auto isSingleStringLiteralArg =
false;
2116 if (CE->getNumArgs() == 1) {
2117 isSingleStringLiteralArg =
2120 if (!isSingleStringLiteralArg) {
2123 Result.addNode(Tag, DynTypedNode::create(*CE));
2127 Result.addNode(Tag, DynTypedNode::create(*CE));
2128 Result.addNode(UnsafeVaListTag, DynTypedNode::create(*FD));
2132 Result.addNode(Tag, DynTypedNode::create(*CE));
2133 Result.addNode(UnsafeSprintfTag, DynTypedNode::create(*FD));
2139 Result.addNode(Tag, DynTypedNode::create(*CE));
2140 Result.addNode(UnsafeSizedByTag, DynTypedNode::create(*CE));
2145 Result.addNode(Tag, DynTypedNode::create(*CE));
2152 const Stmt *getBaseStmt()
const {
return Call; }
2154 SourceLocation getSourceLoc()
const override {
return Call->getBeginLoc(); }
2156 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2157 bool IsRelatedToDecl,
2158 ASTContext &Ctx)
const override {
2162 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2164 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2170class ULCArraySubscriptGadget :
public FixableGadget {
2172 static constexpr const char *
const ULCArraySubscriptTag =
2173 "ArraySubscriptUnderULC";
2174 const ArraySubscriptExpr *Node;
2178 : FixableGadget(
Kind::ULCArraySubscript),
2179 Node(
Result.getNodeAs<ArraySubscriptExpr>(ULCArraySubscriptTag)) {
2180 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2183 static bool classof(
const Gadget *G) {
2184 return G->getKind() == Kind::ULCArraySubscript;
2187 static bool matches(
const Stmt *S,
2188 llvm::SmallVectorImpl<MatchResult> &Results) {
2189 size_t SizeBefore = Results.size();
2191 const auto *ASE = dyn_cast<ArraySubscriptExpr>(E);
2197 !isSupportedVariable(*DRE))
2200 R.addNode(ULCArraySubscriptTag, DynTypedNode::create(*ASE));
2201 Results.emplace_back(std::move(R));
2203 return SizeBefore != Results.size();
2206 virtual std::optional<FixItList>
2207 getFixits(
const FixitStrategy &S)
const override;
2208 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2210 virtual DeclUseList getClaimedVarUseSites()
const override {
2211 if (
const auto *DRE =
2212 dyn_cast<DeclRefExpr>(Node->getBase()->IgnoreImpCasts())) {
2222class UPCStandalonePointerGadget :
public FixableGadget {
2224 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
2225 const DeclRefExpr *Node;
2229 : FixableGadget(
Kind::UPCStandalonePointer),
2230 Node(
Result.getNodeAs<DeclRefExpr>(DeclRefExprTag)) {
2231 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2234 static bool classof(
const Gadget *G) {
2235 return G->getKind() == Kind::UPCStandalonePointer;
2238 static bool matches(
const Stmt *S,
2239 llvm::SmallVectorImpl<MatchResult> &Results) {
2240 size_t SizeBefore = Results.size();
2242 auto *E = dyn_cast<Expr>(S);
2247 !isSupportedVariable(*DRE))
2250 R.addNode(DeclRefExprTag, DynTypedNode::create(*DRE));
2251 Results.emplace_back(std::move(R));
2253 return SizeBefore != Results.size();
2256 virtual std::optional<FixItList>
2257 getFixits(
const FixitStrategy &S)
const override;
2258 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2260 virtual DeclUseList getClaimedVarUseSites()
const override {
return {Node}; }
2263class PointerDereferenceGadget :
public FixableGadget {
2264 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2265 static constexpr const char *
const OperatorTag =
"op";
2267 const DeclRefExpr *BaseDeclRefExpr =
nullptr;
2268 const UnaryOperator *Op =
nullptr;
2272 : FixableGadget(
Kind::PointerDereference),
2273 BaseDeclRefExpr(
Result.getNodeAs<DeclRefExpr>(BaseDeclRefExprTag)),
2274 Op(
Result.getNodeAs<UnaryOperator>(OperatorTag)) {}
2276 static bool classof(
const Gadget *G) {
2277 return G->getKind() == Kind::PointerDereference;
2280 static bool matches(
const Stmt *S,
2281 llvm::SmallVectorImpl<MatchResult> &Results) {
2282 size_t SizeBefore = Results.size();
2284 const auto *UO = dyn_cast<UnaryOperator>(S);
2287 const auto *CE = dyn_cast<Expr>(UO->
getSubExpr());
2290 CE = CE->IgnoreParenImpCasts();
2291 const auto *DRE = dyn_cast<DeclRefExpr>(CE);
2292 if (!DRE || !isSupportedVariable(*DRE))
2295 R.addNode(BaseDeclRefExprTag, DynTypedNode::create(*DRE));
2296 R.addNode(OperatorTag, DynTypedNode::create(*UO));
2297 Results.emplace_back(std::move(R));
2299 return SizeBefore != Results.size();
2302 DeclUseList getClaimedVarUseSites()
const override {
2303 return {BaseDeclRefExpr};
2306 virtual std::optional<FixItList>
2307 getFixits(
const FixitStrategy &S)
const override;
2308 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2314class UPCAddressofArraySubscriptGadget :
public FixableGadget {
2316 static constexpr const char *
const UPCAddressofArraySubscriptTag =
2317 "AddressofArraySubscriptUnderUPC";
2318 const UnaryOperator *Node;
2322 : FixableGadget(
Kind::ULCArraySubscript),
2323 Node(
Result.getNodeAs<UnaryOperator>(UPCAddressofArraySubscriptTag)) {
2324 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2327 static bool classof(
const Gadget *G) {
2328 return G->getKind() == Kind::UPCAddressofArraySubscript;
2331 static bool matches(
const Stmt *S,
2332 llvm::SmallVectorImpl<MatchResult> &Results) {
2333 size_t SizeBefore = Results.size();
2335 auto *E = dyn_cast<Expr>(S);
2339 if (!UO || UO->
getOpcode() != UO_AddrOf)
2341 const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->
getSubExpr());
2346 if (!DRE || !isSupportedVariable(*DRE))
2349 R.addNode(UPCAddressofArraySubscriptTag, DynTypedNode::create(*UO));
2350 Results.emplace_back(std::move(R));
2352 return SizeBefore != Results.size();
2355 virtual std::optional<FixItList>
2356 getFixits(
const FixitStrategy &)
const override;
2357 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2359 virtual DeclUseList getClaimedVarUseSites()
const override {
2372class DeclUseTracker {
2373 using UseSetTy = llvm::SmallPtrSet<const DeclRefExpr *, 16>;
2374 using DefMapTy = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
2377 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
2381 DeclUseTracker() =
default;
2382 DeclUseTracker(
const DeclUseTracker &) =
delete;
2383 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
2384 DeclUseTracker(DeclUseTracker &&) =
default;
2385 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
2388 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
2391 void claimUse(
const DeclRefExpr *DRE) {
2392 assert(Uses->count(DRE) &&
2393 "DRE not found or claimed by multiple matchers!");
2398 bool hasUnclaimedUses(
const VarDecl *VD)
const {
2400 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
2405 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
2407 for (
auto use : *Uses) {
2409 ReturnSet.insert(use);
2415 void discoverDecl(
const DeclStmt *DS) {
2416 for (
const Decl *D : DS->
decls()) {
2417 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
2428 const DeclStmt *lookupDecl(
const VarDecl *VD)
const {
2429 return Defs.lookup(VD);
2438 static constexpr const char *
const UPCPreIncrementTag =
2439 "PointerPreIncrementUnderUPC";
2444 : FixableGadget(Kind::UPCPreIncrement),
2446 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2450 return G->getKind() == Kind::UPCPreIncrement;
2459 size_t SizeBefore = Results.size();
2461 auto *E = dyn_cast<Expr>(S);
2465 if (!UO || UO->
getOpcode() != UO_PreInc)
2467 const auto *DRE = dyn_cast<DeclRefExpr>(UO->
getSubExpr());
2468 if (!DRE || !isSupportedVariable(*DRE))
2472 Results.emplace_back(std::move(R));
2474 return SizeBefore != Results.size();
2477 virtual std::optional<FixItList>
2482 return {dyn_cast<DeclRefExpr>(Node->getSubExpr())};
2490 static constexpr const char *
const UUCAddAssignTag =
2491 "PointerAddAssignUnderUUC";
2492 static constexpr const char *
const OffsetTag =
"Offset";
2495 const Expr *Offset =
nullptr;
2499 : FixableGadget(Kind::UUCAddAssign),
2502 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2506 return G->getKind() == Kind::UUCAddAssign;
2511 size_t SizeBefore = Results.size();
2513 const auto *E = dyn_cast<Expr>(S);
2517 if (!BO || BO->
getOpcode() != BO_AddAssign)
2519 const auto *DRE = dyn_cast<DeclRefExpr>(BO->
getLHS());
2525 Results.emplace_back(std::move(R));
2527 return SizeBefore != Results.size();
2530 virtual std::optional<FixItList>
2535 return {dyn_cast<DeclRefExpr>(Node->getLHS())};
2542 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2543 static constexpr const char *
const DerefOpTag =
"DerefOp";
2544 static constexpr const char *
const AddOpTag =
"AddOp";
2545 static constexpr const char *
const OffsetTag =
"Offset";
2554 : FixableGadget(Kind::DerefSimplePtrArithFixable),
2562 auto IsPtr = [](
const Expr *E, MatchResult &R) {
2566 if (!DRE || !isSupportedVariable(*DRE))
2571 const auto IsPlusOverPtrAndInteger = [&IsPtr](
const Expr *E,
2573 const auto *BO = dyn_cast<BinaryOperator>(E);
2577 const auto *LHS = BO->
getLHS();
2578 const auto *RHS = BO->
getRHS();
2591 size_t SizeBefore = Results.size();
2592 const auto InnerMatcher = [&IsPlusOverPtrAndInteger,
2593 &Results](
const Expr *E) {
2594 const auto *UO = dyn_cast<UnaryOperator>(E);
2600 if (IsPlusOverPtrAndInteger(Operand, R)) {
2602 Results.emplace_back(std::move(R));
2606 return SizeBefore != Results.size();
2609 virtual std::optional<FixItList>
2612 return DerefOp->getBeginLoc();
2616 return {BaseDeclRefExpr};
2624 : WarningGadgets(WarningGadgets) {}
2633#define WARNING_GADGET(name) \
2634 if (name##Gadget::matches(S, Ctx, Result) && \
2635 notInSafeBufferOptOut(*S, &Handler)) { \
2636 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2639#define WARNING_OPTIONAL_GADGET(name) \
2640 if (name##Gadget::matches(S, Ctx, &Handler, Result) && \
2641 notInSafeBufferOptOut(*S, &Handler)) { \
2642 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2645#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2650 WarningGadgetList &WarningGadgets;
2657 DeclUseTracker &Tracker)
2658 : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
2662 bool matchFound =
false;
2669#define FIXABLE_GADGET(name) \
2670 if (name##Gadget::matches(S, Results)) { \
2671 for (const auto &R : Results) { \
2672 FixableGadgets.push_back(std::make_unique<name##Gadget>(R)); \
2673 matchFound = true; \
2677#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2680 if (
auto *DRE = findDeclRefExpr(S); DRE) {
2681 Tracker.discoverUse(DRE);
2687 if (
auto *DS = findDeclStmt(S); DS) {
2688 Tracker.discoverDecl(DS);
2696 const auto *DRE = dyn_cast<DeclRefExpr>(S);
2704 const DeclStmt *findDeclStmt(
const Stmt *S) {
2705 const auto *DS = dyn_cast<DeclStmt>(S);
2710 FixableGadgetList &FixableGadgets;
2711 DeclUseTracker &Tracker;
2717 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2718 WarningGadgetList &WarningGadgets,
2719 DeclUseTracker &Tracker) {
2722 if (EmitSuggestions) {
2731 return N1->getBeginLoc().getRawEncoding() <
2732 N2->getBeginLoc().getRawEncoding();
2742 const Expr *UnsafeArg =
nullptr)
override {}
2750 bool IsRelatedToDecl,
2767 FixableGadgetList FixableGadgets;
2768 WarningGadgetList WarningGadgets;
2769 DeclUseTracker Tracker;
2770 MockReporter IgnoreHandler;
2773 FixableGadgets, WarningGadgets, Tracker);
2775 std::set<const Expr *>
Result;
2776 for (
auto &G : WarningGadgets) {
2777 for (
const Expr *E : G->getUnsafePtrs()) {
2786 std::map<const VarDecl *, std::set<const WarningGadget *>,
2800 for (
auto &G : AllUnsafeOperations) {
2801 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
2803 bool AssociatedWithVarDecl =
false;
2804 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
2805 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2806 result.
byVar[VD].insert(G.get());
2807 AssociatedWithVarDecl =
true;
2811 if (!AssociatedWithVarDecl) {
2812 result.
noVar.push_back(G.get());
2820 std::map<const VarDecl *, std::set<const FixableGadget *>,
2830 for (
auto &F : AllFixableOperations) {
2831 DeclUseList DREs = F->getClaimedVarUseSites();
2834 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2835 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
2839 return FixablesForUnsafeVars;
2846 std::vector<const FixItHint *>
All;
2850 std::sort(
All.begin(),
All.end(),
2852 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
2853 H2->RemoveRange.getBegin());
2861 Hint->RemoveRange.getBegin())) {
2873std::optional<FixItList>
2874PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2877 switch (S.
lookup(LeftVD)) {
2881 return std::nullopt;
2883 return std::nullopt;
2886 return std::nullopt;
2888 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2890 return std::nullopt;
2894static inline std::optional<FixItList>
createDataFixit(
const ASTContext &Ctx,
2895 const DeclRefExpr *DRE);
2897std::optional<FixItList>
2898CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2917 if (S.
lookup(LeftVD) == FixitStrategy::Kind::Span) {
2918 if (S.
lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
2921 }
else if (S.
lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
2922 if (S.
lookup(RightVD) == FixitStrategy::Kind::Array) {
2926 return std::nullopt;
2929std::optional<FixItList>
2930PointerInitGadget::getFixits(
const FixitStrategy &S)
const {
2931 const auto *LeftVD = PtrInitLHS;
2933 switch (S.
lookup(LeftVD)) {
2934 case FixitStrategy::Kind::Span:
2935 if (S.
lookup(RightVD) == FixitStrategy::Kind::Span)
2937 return std::nullopt;
2938 case FixitStrategy::Kind::Wontfix:
2939 return std::nullopt;
2940 case FixitStrategy::Kind::Iterator:
2941 case FixitStrategy::Kind::Array:
2942 return std::nullopt;
2943 case FixitStrategy::Kind::Vector:
2944 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2946 return std::nullopt;
2952 if (ConstVal->isNegative())
2959std::optional<FixItList>
2960ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2961 if (
const auto *DRE =
2963 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2965 case FixitStrategy::Kind::Span: {
2969 const ASTContext &Ctx =
2972 return std::nullopt;
2976 case FixitStrategy::Kind::Array:
2978 case FixitStrategy::Kind::Wontfix:
2979 case FixitStrategy::Kind::Iterator:
2980 case FixitStrategy::Kind::Vector:
2981 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2984 return std::nullopt;
2987static std::optional<FixItList>
2990std::optional<FixItList>
2991UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2992 auto DREs = getClaimedVarUseSites();
2996 case FixitStrategy::Kind::Span:
2998 case FixitStrategy::Kind::Wontfix:
2999 case FixitStrategy::Kind::Iterator:
3000 case FixitStrategy::Kind::Array:
3001 return std::nullopt;
3002 case FixitStrategy::Kind::Vector:
3003 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3005 return std::nullopt;
3010 static const char *
const EOL =
"\n";
3017 std::string
s = std::string(
"<# ");
3018 s += HintTextToUser;
3024template <
typename NodeTy>
3025static std::optional<SourceLocation>
3028 if (
unsigned TkLen =
3035 return std::nullopt;
3048 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
3049 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
3050 VD->getBeginLoc())) &&
3051 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
3052 At->getRange().getBegin()));
3056 AttrRangeOverlapping;
3098 std::optional<Qualifiers> Quals = std::nullopt) {
3099 const char *
const SpanOpen =
"std::span<";
3102 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
3103 return SpanOpen + EltTyText.str() +
'>';
3106std::optional<FixItList>
3108 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->getDecl());
3113 if (
auto ConstVal = Offset->getIntegerConstantExpr(Ctx))
3114 if (ConstVal->isNegative())
3115 return std::nullopt;
3136 const Expr *LHS = AddOp->getLHS(), *RHS = AddOp->getRHS();
3143 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
3145 return std::nullopt;
3150 std::optional<SourceLocation> AddOpLocation =
3152 std::optional<SourceLocation> DerefOpLocation =
3155 if (!AddOpLocation || !DerefOpLocation)
3156 return std::nullopt;
3166 return std::nullopt;
3169std::optional<FixItList>
3170PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
3181 if (
auto LocPastOperand =
3188 case FixitStrategy::Kind::Iterator:
3189 case FixitStrategy::Kind::Array:
3190 return std::nullopt;
3191 case FixitStrategy::Kind::Vector:
3192 llvm_unreachable(
"FixitStrategy not implemented yet!");
3193 case FixitStrategy::Kind::Wontfix:
3194 llvm_unreachable(
"Invalid strategy!");
3197 return std::nullopt;
3204 std::optional<SourceLocation> EndOfOperand =
3210 return std::nullopt;
3215std::optional<FixItList>
3216UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
3219 case FixitStrategy::Kind::Array:
3220 case FixitStrategy::Kind::Span: {
3225 case FixitStrategy::Kind::Wontfix:
3226 case FixitStrategy::Kind::Iterator:
3227 return std::nullopt;
3228 case FixitStrategy::Kind::Vector:
3229 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3232 return std::nullopt;
3237static std::optional<FixItList>
3244 const Expr *Idx = ArraySub->getIdx();
3247 std::stringstream SS;
3248 bool IdxIsLitZero =
false;
3251 if ((*ICE).isZero())
3252 IdxIsLitZero =
true;
3253 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
3255 return std::nullopt;
3259 SS << (*DreString).str() <<
".data()";
3261 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
3263 return std::nullopt;
3265 SS <<
"&" << (*DreString).str() <<
".data()"
3266 <<
"[" << (*IndexString).str() <<
"]";
3272std::optional<FixItList>
3276 if (DREs.size() != 1)
3277 return std::nullopt;
3279 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3283 const Stmt *AddAssignNode = Node;
3284 StringRef varName = VD->
getName();
3288 return std::nullopt;
3292 (Offset->IgnoreParens()->getBeginLoc() == Offset->getBeginLoc());
3293 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
3297 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
3299 if (!AddAssignLocation)
3300 return std::nullopt;
3307 Offset->getEndLoc().getLocWithOffset(1),
")"));
3311 return std::nullopt;
3314std::optional<FixItList>
3318 if (DREs.size() != 1)
3319 return std::nullopt;
3321 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3324 std::stringstream SS;
3325 StringRef varName = VD->
getName();
3329 SS <<
"(" << varName.data() <<
" = " << varName.data()
3330 <<
".subspan(1)).data()";
3331 std::optional<SourceLocation> PreIncLocation =
3333 if (!PreIncLocation)
3334 return std::nullopt;
3337 SourceRange(Node->getBeginLoc(), *PreIncLocation), SS.str()));
3341 return std::nullopt;
3359static std::optional<FixItList>
3361 const StringRef UserFillPlaceHolder) {
3369 if (
Init->isNullPointerConstant(
3374 NPC_ValueDependentIsNotNull)) {
3375 std::optional<SourceLocation> InitLocation =
3378 return std::nullopt;
3386 std::string ExtentText = UserFillPlaceHolder.data();
3387 StringRef One =
"1";
3392 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
3397 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
3398 if (!Ext->HasSideEffects(Ctx)) {
3399 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
3401 return std::nullopt;
3402 ExtentText = *ExtentString;
3404 }
else if (!CxxNew->isArray())
3416 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
3417 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
3418 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
3425 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
3428 return std::nullopt;
3430 StrBuffer.append(
", ");
3431 StrBuffer.append(ExtentText);
3432 StrBuffer.append(
"}");
3438#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
3439 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
3440 "failed to produce fixit for declaration '" + \
3441 (D)->getNameAsString() + "'" + (Msg))
3443#define DEBUG_NOTE_DECL_FAIL(D, Msg)
3449static std::optional<std::string>
3453 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3458 return std::nullopt;
3460 std::string SpanTyText =
"std::span<";
3462 SpanTyText.append(*PteTyText);
3464 if (PteTyQualifiers) {
3465 SpanTyText.append(
" ");
3466 SpanTyText.append(PteTyQualifiers->getAsString());
3468 SpanTyText.append(
">");
3487 const StringRef UserFillPlaceHolder,
3501 std::stringstream SS;
3506 std::optional<FixItList> InitFixIts =
3510 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
3511 std::make_move_iterator(InitFixIts->end()));
3518 if (!EndLocForReplacement.
isValid()) {
3568static std::optional<FixItList>
3574 return std::nullopt;
3579 std::vector<std::string> NewTysTexts(NumParms);
3580 std::vector<bool> ParmsMask(NumParms,
false);
3581 bool AtLeastOneParmToFix =
false;
3583 for (
unsigned i = 0; i < NumParms; i++) {
3590 return std::nullopt;
3592 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3593 std::optional<std::string> PteTyText =
3598 return std::nullopt;
3602 ParmsMask[i] =
true;
3603 AtLeastOneParmToFix =
true;
3605 if (!AtLeastOneParmToFix)
3612 const auto NewOverloadSignatureCreator =
3613 [&
SM, &LangOpts, &NewTysTexts,
3614 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3615 std::stringstream SS;
3623 SS << Prefix->str();
3625 return std::nullopt;
3629 for (
unsigned i = 0; i < NumParms; i++) {
3637 SS << NewTysTexts[i];
3640 SS <<
' ' << II->getName().str();
3641 }
else if (
auto ParmTypeText =
3645 SS << ParmTypeText->str();
3647 return std::nullopt;
3648 if (i != NumParms - 1)
3657 const auto OldOverloadDefCreator =
3658 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3659 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3660 std::stringstream SS;
3668 << FDPrefix->str() <<
"{";
3670 return std::nullopt;
3673 SS <<
"return " << FunQualName->str() <<
"(";
3675 return std::nullopt;
3679 for (
unsigned i = 0; i < NumParms; i++) {
3688 return std::nullopt;
3695 if (i != NumParms - 1)
3706 std::optional<SourceLocation> Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3710 if (FReDecl->isThisDeclarationADefinition()) {
3711 assert(FReDecl == FD &&
"inconsistent function definition");
3714 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3720 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3723 FReDecl->getBeginLoc(),
" ")));
3726 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3748 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3764 std::stringstream SS;
3767 if (PteTyQualifiers)
3776 SS <<
' ' << PVDNameText->str();
3782 const DeclUseTracker &Tracker,
3785 const DeclStmt *DS = Tracker.lookupDecl(VD);
3788 " : variables declared this way not implemented yet");
3812 const QualType &ArrayEltT = CAT->getElementType();
3813 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
3822 auto MaybeElemTypeTxt =
3825 if (!MaybeElemTypeTxt)
3827 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
3832 while (NextTok && !NextTok->is(tok::l_square) &&
3845 if (!MaybeArraySizeTxt)
3847 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
3848 if (ArraySizeTxt.empty()) {
3859 std::optional<StringRef> IdentText =
3868 llvm::raw_svector_ostream OS(Replacement);
3869 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
3870 << IdentText->str();
3880 const DeclUseTracker &Tracker,
3883 const DeclStmt *DS = Tracker.lookupDecl(VD);
3884 assert(DS &&
"Fixing non-local variables not implemented yet!");
3903 const DeclUseTracker &Tracker,
ASTContext &Ctx,
3905 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
3906 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
3907 if (!FD || FD != D) {
3918 if (FD->isMain() || FD->isConstexpr() ||
3925 FD->isOverloadedOperator()) {
3934 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
3952 llvm_unreachable(
"FixitStrategy not implemented yet!");
3954 llvm_unreachable(
"Invalid strategy!");
3956 llvm_unreachable(
"Unknown strategy!");
3964 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
3966 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
3983 std::map<const VarDecl *, FixItList> &FixItsForVariable,
3988 for (
const auto &[VD, Ignore] : FixItsForVariable) {
3990 if (llvm::any_of(Grp,
3991 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
3992 return !FixItsForVariable.count(GrpMember);
3997 ToErase.push_back(
Member);
4000 for (
auto *VarToErase : ToErase)
4001 FixItsForVariable.erase(VarToErase);
4012 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
4016 FixItList FixItsSharedByParms{};
4018 std::optional<FixItList> OverloadFixes =
4021 if (OverloadFixes) {
4022 FixItsSharedByParms.append(*OverloadFixes);
4028 FixItsForVariable.erase(
Member);
4030 return FixItsSharedByParms;
4034static std::map<const VarDecl *, FixItList>
4043 std::map<const VarDecl *, FixItList> FixItsForVariable;
4048 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
4049 FixItsForVariable[VD] =
4053 if (FixItsForVariable[VD].empty()) {
4054 FixItsForVariable.erase(VD);
4057 for (
const auto &F : Fixables) {
4058 std::optional<FixItList> Fixits = F->getFixits(S);
4061 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
4062 Fixits->begin(), Fixits->end());
4067 VD, F->getSourceLoc(),
4068 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
4071 FixItsForVariable.erase(VD);
4090 FixItList FixItsSharedByParms{};
4092 if (
auto *FD = dyn_cast<FunctionDecl>(D))
4094 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
4098 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
4101 for (
auto &[Var, Ignore] : FixItsForVariable) {
4102 bool AnyParm =
false;
4103 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
4105 for (
const VarDecl *GrpMate : VarGroupForVD) {
4108 if (FixItsForVariable.count(GrpMate))
4109 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
4113 assert(!FixItsSharedByParms.empty() &&
4114 "Should not try to fix a parameter that does not belong to a "
4116 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
4123 for (
auto Iter = FinalFixItsForVariable.begin();
4124 Iter != FinalFixItsForVariable.end();)
4127 Iter = FinalFixItsForVariable.erase(Iter);
4130 return FinalFixItsForVariable;
4133template <
typename VarDeclIterTy>
4137 for (
const VarDecl *VD : UnsafeVars) {
4148 const std::vector<VarGrpTy> Groups;
4149 const std::map<const VarDecl *, unsigned> &VarGrpMap;
4150 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
4154 const std::vector<VarGrpTy> &Groups,
4155 const std::map<const VarDecl *, unsigned> &VarGrpMap,
4156 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
4157 : Groups(Groups), VarGrpMap(VarGrpMap),
4158 GrpsUnionForParms(GrpsUnionForParms) {}
4161 if (GrpsUnionForParms.contains(Var)) {
4164 return GrpsUnionForParms.getArrayRef();
4169 auto It = VarGrpMap.find(Var);
4171 if (It == VarGrpMap.end())
4173 return Groups[It->second];
4177 return GrpsUnionForParms.getArrayRef();
4182 WarningGadgetList WarningGadgets,
4183 DeclUseTracker Tracker,
4185 bool EmitSuggestions) {
4186 if (!EmitSuggestions) {
4190 for (
const auto &G : WarningGadgets) {
4191 G->handleUnsafeOperation(Handler,
false,
4197 assert(FixableGadgets.empty() &&
4198 "Fixable gadgets found but suggestions not requested!");
4204 if (!WarningGadgets.empty()) {
4208 for (
const auto &G : FixableGadgets) {
4209 for (
const auto *DRE : G->getClaimedVarUseSites()) {
4210 Tracker.claimUse(DRE);
4226 if (WarningGadgets.empty())
4234 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
4237 for (
auto it = FixablesForAllVars.
byVar.cbegin();
4238 it != FixablesForAllVars.
byVar.cend();) {
4243 (
"failed to produce fixit for '" +
4244 it->first->getNameAsString() +
4245 "' : neither local nor a parameter"));
4247 it = FixablesForAllVars.
byVar.erase(it);
4248 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
4251 (
"failed to produce fixit for '" +
4252 it->first->getNameAsString() +
4253 "' : has a reference type"));
4255 it = FixablesForAllVars.
byVar.erase(it);
4256 }
else if (Tracker.hasUnclaimedUses(it->first)) {
4257 it = FixablesForAllVars.
byVar.erase(it);
4258 }
else if (it->first->isInitCapture()) {
4261 (
"failed to produce fixit for '" +
4262 it->first->getNameAsString() +
4263 "' : init capture"));
4265 it = FixablesForAllVars.
byVar.erase(it);
4272 for (
const auto &it : UnsafeOps.
byVar) {
4273 const VarDecl *
const UnsafeVD = it.first;
4274 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
4275 if (UnclaimedDREs.empty())
4279 std::string UnclaimedUseTrace =
4284 (
"failed to produce fixit for '" + UnfixedVDName +
4285 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
4286 UnclaimedUseTrace));
4293 llvm::DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
4294 DepMapTy DependenciesMap{};
4295 DepMapTy PtrAssignmentGraph{};
4297 for (
const auto &it : FixablesForAllVars.
byVar) {
4298 for (
const FixableGadget *fixable : it.second) {
4299 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
4300 fixable->getStrategyImplications();
4302 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
4303 PtrAssignmentGraph[Impl.first].insert(Impl.second);
4325 std::set<const VarDecl *> VisitedVarsDirected{};
4326 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4327 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
4329 std::queue<const VarDecl *> QueueDirected{};
4330 QueueDirected.push(Var);
4331 while (!QueueDirected.empty()) {
4332 const VarDecl *CurrentVar = QueueDirected.front();
4333 QueueDirected.pop();
4334 VisitedVarsDirected.insert(CurrentVar);
4335 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
4336 for (
const VarDecl *Adj : AdjacentNodes) {
4337 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
4338 QueueDirected.push(Adj);
4340 DependenciesMap[Var].insert(Adj);
4341 DependenciesMap[Adj].insert(Var);
4348 std::vector<VarGrpTy> Groups;
4352 std::map<const VarDecl *, unsigned> VarGrpMap;
4354 llvm::SetVector<const VarDecl *>
4359 std::set<const VarDecl *> VisitedVars{};
4360 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4361 if (VisitedVars.find(Var) == VisitedVars.end()) {
4362 VarGrpTy &VarGroup = Groups.emplace_back();
4363 std::queue<const VarDecl *> Queue{};
4366 while (!Queue.empty()) {
4367 const VarDecl *CurrentVar = Queue.front();
4369 VisitedVars.insert(CurrentVar);
4370 VarGroup.push_back(CurrentVar);
4371 auto AdjacentNodes = DependenciesMap[CurrentVar];
4372 for (
const VarDecl *Adj : AdjacentNodes) {
4373 if (VisitedVars.find(Adj) == VisitedVars.end()) {
4379 bool HasParm =
false;
4380 unsigned GrpIdx = Groups.size() - 1;
4382 for (
const VarDecl *
V : VarGroup) {
4383 VarGrpMap[
V] = GrpIdx;
4388 GrpsUnionForParms.insert_range(VarGroup);
4410 for (
auto I = FixablesForAllVars.
byVar.begin();
4411 I != FixablesForAllVars.
byVar.end();) {
4413 if (!VisitedVars.count((*I).first)) {
4415 I = FixablesForAllVars.
byVar.erase(I);
4423 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
4425 return FixablesForAllVars.
byVar.count(
V);
4432 FixItsForVariableGroup =
4434 Tracker, Handler, VarGrpMgr);
4436 for (
const auto &G : UnsafeOps.
noVar) {
4437 G->handleUnsafeOperation(Handler,
false,
4441 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
4442 auto FixItsIt = FixItsForVariableGroup.find(VD);
4444 FixItsIt != FixItsForVariableGroup.end()
4445 ? std::move(FixItsIt->second)
4448 for (
const auto &G : WarningGadgets) {
4449 G->handleUnsafeOperation(Handler,
true,
4457 bool EmitSuggestions) {
4466 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
4470 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
4471 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
4476 if (FReDecl->isExternC()) {
4479 EmitSuggestions =
false;
4484 Stmts.push_back(FD->getBody());
4486 if (
const auto *ID = dyn_cast<CXXConstructorDecl>(D)) {
4488 Stmts.push_back(CI->getInit());
4492 Stmts.push_back(D->
getBody());
4495 assert(!Stmts.empty());
4497 FixableGadgetList FixableGadgets;
4498 WarningGadgetList WarningGadgets;
4499 DeclUseTracker Tracker;
4500 for (
Stmt *S : Stmts) {
4502 WarningGadgets, Tracker);
4504 applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
4505 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 bool isSafeArraySubscript(const ArraySubscriptExpr &Node, const ASTContext &Ctx)
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 std::optional< FixItList > createDataFixit(const ASTContext &Ctx, const DeclRefExpr *DRE)
static FixItList createFunctionOverloadsForParms(std::map< const VarDecl *, FixItList > &FixItsForVariable, const VariableGroupsManager &VarGrpMgr, const FunctionDecl *FD, const FixitStrategy &S, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static bool isNullTermPointer(const Expr *Ptr, ASTContext &Ctx)
static bool isSafeSpanTwoParamConstruct(const CXXConstructExpr &Node, ASTContext &Ctx)
static FixItList fixVarDeclWithArray(const VarDecl *D, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static FixItList fixVariable(const VarDecl *VD, FixitStrategy::Kind K, const Decl *D, const DeclUseTracker &Tracker, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static FixItList fixParamWithSpan(const ParmVarDecl *PVD, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static FixitStrategy getNaiveStrategy(llvm::iterator_range< VarDeclIterTy > UnsafeVars)
static std::optional< std::string > createSpanTypeForVarDecl(const VarDecl *VD, const ASTContext &Ctx)
static bool hasConflictingOverload(const FunctionDecl *FD)
static void findStmtsInUnspecifiedPointerContext(const Stmt *S, llvm::function_ref< void(const Stmt *)> InnerMatcher)
static bool isNonNegativeIntegerExpr(const Expr *Expr, const VarDecl *VD, const ASTContext &Ctx)
static bool overlapWithMacro(const FixItList &FixIts)
static void forEachDescendantStmt(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, FastMatcher &Matcher)
static bool hasUnsupportedSpecifiers(const VarDecl *VD, const SourceManager &SM)
static const Expr * tryConstantFoldConditionalExpr(const Expr *E, const ASTContext &Ctx)
#define DEBUG_NOTE_DECL_FAIL(D, Msg)
static void applyGadgets(const Decl *D, FixableGadgetList FixableGadgets, WarningGadgetList WarningGadgets, DeclUseTracker Tracker, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
static bool areEqualIntegers(const Expr *E1, const Expr *E2, ASTContext &Ctx)
static void findGadgets(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, bool EmitSuggestions, FixableGadgetList &FixableGadgets, WarningGadgetList &WarningGadgets, DeclUseTracker &Tracker)
static std::map< const VarDecl *, FixItList > getFixIts(FixableGadgetSets &FixablesForAllVars, const FixitStrategy &S, ASTContext &Ctx, const Decl *D, const DeclUseTracker &Tracker, UnsafeBufferUsageHandler &Handler, const VariableGroupsManager &VarGrpMgr)
static bool isPtrBufferSafe(const Expr *Ptr, const Expr *Size, ASTContext &Ctx)
static void forEachDescendantEvaluatedStmt(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, FastMatcher &Matcher)
static void findStmtsInUnspecifiedUntypedContext(const Stmt *S, llvm::function_ref< void(const Stmt *)> InnerMatcher)
static std::optional< FixItList > createOverloadsForFixedParams(const FixitStrategy &S, const FunctionDecl *FD, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static void eraseVarsForUnfixableGroupMates(std::map< const VarDecl *, FixItList > &FixItsForVariable, const VariableGroupsManager &VarGrpMgr)
static FixableGadgetSets groupFixablesByVar(FixableGadgetList &&AllFixableOperations)
static bool isParameterOf(const VarDecl *VD, const Decl *D)
#define SIZED_CONTAINER_OR_VIEW_LIST
static std::optional< StringRef > getFunNameText(const FunctionDecl *FD, const SourceManager &SM, const LangOptions &LangOpts)
__device__ __2f16 float __ockl_bool s
virtual std::optional< FixItList > getFixits(const FixitStrategy &s) const final
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
DerefSimplePtrArithFixableGadget(const MatchResult &Result)
SourceLocation getSourceLoc() const override
virtual DeclUseList getClaimedVarUseSites() const final
FixableGadgetMatcher(FixableGadgetList &FixableGadgets, DeclUseTracker &Tracker)
bool matches(const DynTypedNode &DynNode, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler) override
Represents the length modifier in a format string in scanf/printf.
bool TraverseCXXTypeidExpr(CXXTypeidExpr *Node) override
MatchDescendantVisitor(ASTContext &Context, FastMatcher &Matcher, bool FindAll, bool ignoreUnevaluatedContext, const UnsafeBufferUsageHandler &NewHandler)
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc Node, bool TraverseQualifier) override
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc Node, bool TraverseQualifier) override
bool TraverseGenericSelectionExpr(GenericSelectionExpr *Node) override
bool TraverseDecl(Decl *Node) override
bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) override
bool findMatch(const DynTypedNode &DynNode)
bool TraverseCXXDefaultInitExpr(CXXDefaultInitExpr *Node) override
bool TraverseCXXNoexceptExpr(CXXNoexceptExpr *Node) override
bool TraverseStmt(Stmt *Node) override
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
SourceLocation getSourceLoc() const override
virtual DeclUseList getClaimedVarUseSites() const override
UPCPreIncrementGadget(const MatchResult &Result)
static bool classof(const Gadget *G)
static bool classof(const Gadget *G)
UUCAddAssignGadget(const MatchResult &Result)
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
virtual DeclUseList getClaimedVarUseSites() const override
SourceLocation getSourceLoc() const override
VariableGroupsManagerImpl(const std::vector< VarGrpTy > &Groups, const std::map< const VarDecl *, unsigned > &VarGrpMap, const llvm::SetVector< const VarDecl * > &GrpsUnionForParms)
VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm) const override
Returns the set of variables (including Var) that need to be fixed together in one step.
VarGrpRef getGroupOfParms() const override
Returns the non-empty group of variables that include parameters of the analyzing function,...
bool matches(const DynTypedNode &DynNode, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler) override
WarningGadgetMatcher(WarningGadgetList &WarningGadgets)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
const ConstantArrayType * getAsConstantArrayType(QualType T) const
DynTypedNodeList getParents(const NodeT &Node)
Forwards to get node parents from the ParentMapContext.
QualType getFILEType() const
Retrieve the C FILE type.
const LangOptions & getLangOpts() const
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Attr - This represents one attribute.
A builtin binary operation expression such as "x + y" or "x <= y".
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
Represents a call to a C++ constructor.
Expr * getArg(unsigned Arg)
Return the specified argument.
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
Represents a C++ base or member initializer.
A use of a default initializer in a constructor or in aggregate initialization.
Expr * getExpr()
Get the initialization expression that will be used.
Represents a static or instance method of a struct/union/class.
Represents a C++11 noexcept expression (C++ [expr.unary.noexcept]).
OverloadedOperatorKind getOperator() const
Returns the kind of overloaded operator that this expression refers to.
Represents a C++ struct/union/class.
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
A C++ typeid expression (C++ [expr.typeid]), which gets the type_info that corresponds to the supplie...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
static const char * getCastKindName(CastKind CK)
Represents a character-granular source range.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getEnd() const
bool isOne() const
isOne - Test whether the quantity equals one.
Represents a class template specialization, which refers to a class template with a given set of temp...
const TemplateArgumentList & getTemplateArgs() const
Retrieve the template arguments of the class template specialization.
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
bool isSingleResult() const
DeclContext * getParent()
getParent - Returns the containing DeclContext.
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
A reference to a declared variable, function, enum, etc.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
bool isSingleDecl() const
isSingleDecl - This method returns true if this DeclStmt refers to a single Decl.
const Decl * getSingleDecl() const
Decl - This represents one declaration (or definition), e.g.
bool isInStdNamespace() const
SourceLocation getEndLoc() const LLVM_READONLY
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
DeclContext * getDeclContext()
SourceLocation getBeginLoc() const LLVM_READONLY
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
SourceLocation getTypeSpecEndLoc() const
SourceLocation getBeginLoc() const LLVM_READONLY
NestedNameSpecifierLoc getQualifierLoc() const
Retrieve the nested-name-specifier (with source-location information) that qualifies the name of this...
NestedNameSpecifier getQualifier() const
Retrieve the nested-name-specifier that qualifies the name of this declaration, if it was present in ...
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
const DynTypedNode * begin() const
A dynamically typed AST node container.
const T * get() const
Retrieve the stored node as type T.
static DynTypedNode create(const T &Node)
Creates a DynTypedNode from Node.
virtual bool TraverseDecl(MaybeConst< Decl > *D)
bool ShouldVisitTemplateInstantiations
bool ShouldVisitImplicitCode
virtual bool TraverseStmt(MaybeConst< Stmt > *S)
This represents one expression.
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
bool isValueDependent() const
Determines whether the value of this expression depends on.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
NullPointerConstantValueDependence
Enumeration used to describe how isNullPointerConstant() should cope with value-dependent expressions...
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
static FixItHint CreateRemoval(CharSourceRange RemoveRange)
Create a code modification hint that removes the given source range.
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
Kind lookup(const VarDecl *VD) const
void set(const VarDecl *VD, Kind K)
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
unsigned getBuiltinID(bool ConsiderWrapperFunctions=false) const
Returns a value indicating whether this function corresponds to a builtin function.
param_iterator param_begin()
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
DeclarationNameInfo getNameInfo() const
Represents a C11 generic selection.
Expr * getResultExpr()
Return the result expression of this controlling expression.
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
A simple pair of identifier info and location.
static IntegerLiteral * Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l)
Returns a new integer literal with value 'V' and type 'type'.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static std::optional< Token > findNextToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts, bool IncludeComments=false)
Finds the token that comes right after the given location.
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)
Computes the source location just past the end of the token at this source location.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
SourceLocation getBeginLoc() const
Retrieve the location of the beginning of this nested-name-specifier.
A single parameter index whose accessors require each use to make explicit the parameter index encodi...
bool isValid() const
Is this parameter index valid?
unsigned getASTIndex() const
Get the parameter index as it would normally be encoded at the AST level of representation: zero-orig...
Represents a parameter to a function.
bool hasDefaultArg() const
Determines whether this parameter has a default argument, either parsed or not.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
PointerType - C99 6.7.5.1 - Pointer Declarators.
A (possibly-)qualified type.
bool hasQualifiers() const
Determine whether this type has any qualifiers.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
QualType getCanonicalType() const
bool isConstQualified() const
Determine whether this type is const-qualified.
std::string getAsString() const
Represents a struct/union/class.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
Stmt - This represents one statement.
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const char * getStmtClassName() const
SourceLocation getBeginLoc() const LLVM_READONLY
Exposes information about the current target.
A template argument list.
unsigned size() const
Retrieve the number of template arguments in this template argument list.
Represents a template argument.
QualType getAsType() const
Retrieve the type for a type template argument.
@ Type
The template argument is a type.
ArgKind getKind() const
Return the kind of stored template argument.
The base class of the type hierarchy.
bool isConstantSizeType() const
Return true if this is not a variable sized type, according to the rules of C99 6....
bool isPointerType() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
const T * castAs() const
Member-template castAs<specific type>.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isAnyCharacterType() const
Determine whether this type is any of the built-in character types.
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
bool isAnyPointerType() const
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
static bool isIncrementOp(Opcode Op)
SourceLocation getBeginLoc() const LLVM_READONLY
static bool isDecrementOp(Opcode Op)
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
The interface that lets the caller handle unsafe buffer usage analysis results by overriding this cla...
virtual void handleUnsafeUniquePtrArrayAccess(const DynTypedNode &Node, bool IsRelatedToDecl, ASTContext &Ctx)=0
void addDebugNoteForVar(const VarDecl *VD, SourceLocation Loc, std::string Text)
virtual std::string getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, StringRef WSSuffix="") const =0
virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const =0
virtual bool ignoreUnsafeBufferInContainer(const SourceLocation &Loc) const =0
virtual void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation over raw pointers is found.
virtual void handleUnsafeVariableGroup(const VarDecl *Variable, const VariableGroupsManager &VarGrpMgr, FixItList &&Fixes, const Decl *D, const FixitStrategy &VarTargetTypes)=0
Invoked when a fix is suggested against a variable.
virtual void handleUnsafeOperationInContainer(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation with a std container is found.
virtual bool 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,...
bool hasDataArgument() const
HowSpecified getHowSpecified() const
unsigned getConstantAmount() const
unsigned getPositionalArgIndex() 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)
std::vector< const VarDecl * > VarGrpTy
std::optional< StringRef > getExprText(const Expr *E, const SourceManager &SM, const LangOptions &LangOpts)
static bool classof(const Stmt *T)
@ Result
The result type of a method or function.
const FunctionProtoType * T
std::optional< std::string > getPointeeTypeText(const DeclaratorDecl *VD, const SourceManager &SM, const LangOptions &LangOpts, std::optional< Qualifiers > *QualifiersToAppend)
std::optional< StringRef > getRangeText(SourceRange SR, const SourceManager &SM, const LangOptions &LangOpts)
std::optional< StringRef > getVarDeclIdentifierText(const DeclaratorDecl *VD, const SourceManager &SM, const LangOptions &LangOpts)
std::optional< SourceLocation > getPastLoc(const NodeTy *Node, const SourceManager &SM, const LangOptions &LangOpts)
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
std::set< const Expr * > findUnsafePointers(const FunctionDecl *FD)
ArrayRef< const VarDecl * > VarGrpRef
static bool hasUnsafePrintfStringArg(const CallExpr &Node, ASTContext &Ctx, MatchResult &Result, llvm::StringRef Tag)
static bool hasUnsafeFormatOrSArg(const CallExpr *Call, const Expr *&UnsafeArg, const unsigned FmtArgIdx, ASTContext &Ctx, bool isKprintf=false)
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 isNormalPrintfFunc(const FunctionDecl &Node)
bool operator()(const NodeTy *N1, const NodeTy *N2) const
std::map< const VarDecl *, std::set< const FixableGadget * >, CompareNode< VarDecl > > byVar
std::map< const VarDecl *, std::set< const WarningGadget * >, CompareNode< VarDecl > > byVar
llvm::SmallVector< const WarningGadget *, 16 > noVar
SourceLocation getBeginLoc() const
getBeginLoc - Retrieve the location of the first token.
SourceLocation getEndLoc() const LLVM_READONLY
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.
const BoundNodes Nodes
Contains the nodes bound on the current match.
StringRef matchLibcName(StringRef Name)
StringRef matchName(StringRef FunName, bool isBuiltin)
StringRef matchLibcNameOrBuiltinChk(StringRef Name)