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)
755 StringRef
matchName(StringRef FunName,
bool isBuiltin) {
757 if (isBuiltin && FunName.starts_with(
"__builtin_"))
761 FunName.drop_front(10 ));
763 if (FunName.starts_with(
"__asan_"))
771 if (Name.starts_with(
"__") && Name.ends_with(
"_chk"))
773 Name.drop_front(2).drop_back(4) );
778 if (Name.ends_with(
"_s"))
779 return Name.drop_back(2 );
812 bool isKprintf =
false) {
813 class StringFormatStringHandler
817 const Expr *&UnsafeArg;
831 unsigned PArgIdx = -1;
835 if (0 < PArgIdx && PArgIdx < Call->getNumArgs()) {
836 const Expr *PArg =
Call->getArg(PArgIdx);
839 if (
auto *CE = dyn_cast<CastExpr>(PArg);
840 CE && CE->getType()->isSignedIntegerType())
841 PArg = CE->getSubExpr();
845 analyze_printf::OptionalAmount::HowSpecified::Constant) {
847 llvm::APSInt PArgVal = llvm::APSInt(
857 StringFormatStringHandler(
const CallExpr *
Call,
unsigned FmtArgIdx,
859 :
Call(
Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx) {}
862 const char *startSpecifier,
863 unsigned specifierLen,
871 if (!(0 < ArgIdx && ArgIdx < Call->getNumArgs()))
875 const Expr *Arg =
Call->getArg(ArgIdx);
885 bool IsArgTypeValid =
888 ?
ArgType->getPointeeType()->isWideCharType()
889 :
ArgType->getPointeeType()->isCharType());
892 Precision && IsArgTypeValid)
896 UnsafeArg =
Call->getArg(ArgIdx);
901 const Expr *Fmt =
Call->getArg(FmtArgIdx);
904 if (SL->getCharByteWidth() == 1) {
905 StringRef FmtStr = SL->getString();
906 StringFormatStringHandler Handler(
Call, FmtArgIdx, UnsafeArg, Ctx);
909 Handler, FmtStr.begin(), FmtStr.end(), Ctx.
getLangOpts(),
913 if (
auto FmtStr = SL->tryEvaluateString(Ctx)) {
914 StringFormatStringHandler Handler(
Call, FmtArgIdx, UnsafeArg, Ctx);
916 Handler, FmtStr->data(), FmtStr->data() + FmtStr->size(),
924 llvm::make_range(
Call->arg_begin() + FmtArgIdx,
Call->arg_end()),
925 [&UnsafeArg](
const Expr *Arg) ->
bool {
926 if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg)) {
944 static std::unique_ptr<std::set<StringRef>> PredefinedNames =
nullptr;
945 if (!PredefinedNames)
947 std::make_unique<std::set<StringRef>, std::set<StringRef>>({
1028 if (PredefinedNames->find(Name) != PredefinedNames->end())
1031 std::string NameWCS = Name.str();
1032 size_t WcsPos = NameWCS.find(
"wcs");
1034 while (WcsPos != std::string::npos) {
1035 NameWCS[WcsPos++] =
's';
1036 NameWCS[WcsPos++] =
't';
1037 NameWCS[WcsPos++] =
'r';
1038 WcsPos = NameWCS.find(
"wcs", WcsPos);
1040 if (PredefinedNames->find(NameWCS) != PredefinedNames->end())
1044 return Name.ends_with(
"scanf");
1059 if (!Name.ends_with(
"printf"))
1061 return Name.starts_with(
"v");
1075 if (!Name.ends_with(
"printf") ||
1077 Name.starts_with(
"v"))
1080 StringRef Prefix = Name.drop_back(6);
1082 if (Prefix.ends_with(
"w"))
1083 Prefix = Prefix.drop_back(1);
1084 return Prefix ==
"s";
1099 if (!Name.ends_with(
"printf") || Name.starts_with(
"v"))
1102 StringRef Prefix = Name.drop_back(6);
1104 if (Prefix.ends_with(
"w"))
1105 Prefix = Prefix.drop_back(1);
1107 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
1115 MatchResult &Result, llvm::StringRef Tag) {
1119 assert(FD &&
"It should have been checked that FD is non-null.");
1137 const Expr *UnsafeArg;
1148 bool isKprintf =
false;
1149 const Expr *UnsafeArg;
1152 isKprintf = II->getName() ==
"kprintf";
1166 const Expr *UnsafeArg;
1177 for (
const auto *Arg : Node.
arguments())
1192 assert(FD &&
"It should have been checked that FD is non-null.");
1207 !Size->getType()->isUnsignedIntegerType())
1236#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1239 Gadget(Kind K) : K(K) {}
1241 Kind
getKind()
const {
return K; }
1244 StringRef getDebugName()
const {
1249#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1251 llvm_unreachable(
"Unhandled Gadget::Kind enum");
1255 virtual bool isWarningGadget()
const = 0;
1258 virtual SourceLocation getSourceLoc()
const = 0;
1263 virtual DeclUseList getClaimedVarUseSites()
const = 0;
1265 virtual ~Gadget() =
default;
1273class WarningGadget :
public Gadget {
1275 WarningGadget(Kind K) : Gadget(K) {}
1277 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1278 bool isWarningGadget() const final {
return true; }
1280 virtual void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1281 bool IsRelatedToDecl,
1282 ASTContext &Ctx)
const = 0;
1284 virtual SmallVector<const Expr *, 1> getUnsafePtrs()
const = 0;
1291class FixableGadget :
public Gadget {
1293 FixableGadget(Kind K) : Gadget(K) {}
1295 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1296 bool isWarningGadget() const final {
return false; }
1301 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1302 return std::nullopt;
1311 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1312 getStrategyImplications()
const {
1313 return std::nullopt;
1317static bool isSupportedVariable(
const DeclRefExpr &Node) {
1329 dyn_cast<ClassTemplateSpecializationDecl>(
RecordDecl);
1330 if (!class_template_specialization_decl)
1335 if (template_args.
size() == 0)
1346class UniquePtrArrayAccessGadget :
public WarningGadget {
1348 static constexpr const char *
const AccessorTag =
"unique_ptr_array_access";
1349 const CXXOperatorCallExpr *AccessorExpr;
1353 : WarningGadget(
Kind::UniquePtrArrayAccess),
1354 AccessorExpr(
Result.getNodeAs<CXXOperatorCallExpr>(AccessorTag)) {
1355 assert(AccessorExpr &&
1356 "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr");
1359 static bool classof(
const Gadget *G) {
1360 return G->getKind() == Kind::UniquePtrArrayAccess;
1363 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1366 const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(S);
1367 if (!OpCall || OpCall->
getOperator() != OO_Subscript)
1374 const CXXMethodDecl *
Method =
1379 if (
Method->getOverloadedOperator() != OO_Subscript)
1383 if (!isUniquePtrArray(RecordDecl))
1386 const Expr *IndexExpr = OpCall->
getArg(1);
1387 clang::Expr::EvalResult Eval;
1393 Result.addNode(AccessorTag, DynTypedNode::create(*OpCall));
1396 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1397 bool IsRelatedToDecl,
1398 ASTContext &Ctx)
const override {
1400 DynTypedNode::create(*AccessorExpr), IsRelatedToDecl, Ctx);
1403 SourceLocation getSourceLoc()
const override {
1405 return AccessorExpr->getOperatorLoc();
1406 return SourceLocation();
1409 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1410 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1413using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1414using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1418class IncrementGadget :
public WarningGadget {
1419 static constexpr const char *
const OpTag =
"op";
1420 const UnaryOperator *Op;
1424 : WarningGadget(
Kind::Increment),
1425 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1427 static bool classof(
const Gadget *G) {
1428 return G->getKind() == Kind::Increment;
1431 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1433 const auto *UO = dyn_cast<UnaryOperator>(S);
1438 Result.addNode(OpTag, DynTypedNode::create(*UO));
1442 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1443 bool IsRelatedToDecl,
1444 ASTContext &Ctx)
const override {
1447 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1449 DeclUseList getClaimedVarUseSites()
const override {
1450 SmallVector<const DeclRefExpr *, 2> Uses;
1451 if (
const auto *DRE =
1452 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1453 Uses.push_back(DRE);
1456 return std::move(Uses);
1459 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1460 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1466class DecrementGadget :
public WarningGadget {
1467 static constexpr const char *
const OpTag =
"op";
1468 const UnaryOperator *Op;
1472 : WarningGadget(
Kind::Decrement),
1473 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1475 static bool classof(
const Gadget *G) {
1476 return G->getKind() == Kind::Decrement;
1479 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1481 const auto *UO = dyn_cast<UnaryOperator>(S);
1486 Result.addNode(OpTag, DynTypedNode::create(*UO));
1490 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1491 bool IsRelatedToDecl,
1492 ASTContext &Ctx)
const override {
1495 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1497 DeclUseList getClaimedVarUseSites()
const override {
1498 if (
const auto *DRE =
1499 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1506 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1507 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1513class ArraySubscriptGadget :
public WarningGadget {
1514 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1515 const ArraySubscriptExpr *ASE;
1520 ASE(
Result.getNodeAs<ArraySubscriptExpr>(ArraySubscrTag)) {}
1522 static bool classof(
const Gadget *G) {
1523 return G->getKind() == Kind::ArraySubscript;
1526 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1528 const auto *ASE = dyn_cast<ArraySubscriptExpr>(S);
1531 const auto *
const Base = ASE->getBase()->IgnoreParenImpCasts();
1534 const auto *Idx = dyn_cast<IntegerLiteral>(ASE->getIdx());
1535 bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
1539 Result.addNode(ArraySubscrTag, DynTypedNode::create(*ASE));
1543 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1544 bool IsRelatedToDecl,
1545 ASTContext &Ctx)
const override {
1548 SourceLocation getSourceLoc()
const override {
return ASE->getBeginLoc(); }
1550 DeclUseList getClaimedVarUseSites()
const override {
1551 if (
const auto *DRE =
1552 dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
1559 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1560 return {ASE->getBase()->IgnoreParenImpCasts()};
1568class PointerArithmeticGadget :
public WarningGadget {
1569 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1570 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1571 const BinaryOperator *PA;
1576 : WarningGadget(
Kind::PointerArithmetic),
1577 PA(
Result.getNodeAs<BinaryOperator>(PointerArithmeticTag)),
1578 Ptr(
Result.getNodeAs<Expr>(PointerArithmeticPointerTag)) {}
1580 static bool classof(
const Gadget *G) {
1581 return G->getKind() == Kind::PointerArithmetic;
1584 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1586 const auto *BO = dyn_cast<BinaryOperator>(S);
1589 const auto *LHS = BO->
getLHS();
1590 const auto *RHS = BO->
getRHS();
1595 RHS->getType()->isEnumeralType())) {
1596 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*LHS));
1597 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1603 (LHS->getType()->isIntegerType() || LHS->getType()->isEnumeralType())) {
1604 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*RHS));
1605 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1611 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1612 bool IsRelatedToDecl,
1613 ASTContext &Ctx)
const override {
1616 SourceLocation getSourceLoc()
const override {
return PA->getBeginLoc(); }
1618 DeclUseList getClaimedVarUseSites()
const override {
1619 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts())) {
1626 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1627 return {Ptr->IgnoreParenImpCasts()};
1634class SpanTwoParamConstructorGadget :
public WarningGadget {
1635 static constexpr const char *
const SpanTwoParamConstructorTag =
1636 "spanTwoParamConstructor";
1637 const CXXConstructExpr *Ctor;
1641 : WarningGadget(
Kind::SpanTwoParamConstructor),
1642 Ctor(
Result.getNodeAs<CXXConstructExpr>(SpanTwoParamConstructorTag)) {}
1644 static bool classof(
const Gadget *G) {
1645 return G->getKind() == Kind::SpanTwoParamConstructor;
1649 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1652 const auto *CDecl = CE->getConstructor();
1653 const auto *CRecordDecl = CDecl->getParent();
1654 auto HasTwoParamSpanCtorDecl =
1655 CRecordDecl->isInStdNamespace() &&
1656 CDecl->getDeclName().getAsString() ==
"span" && CE->getNumArgs() == 2;
1659 Result.addNode(SpanTwoParamConstructorTag, DynTypedNode::create(*CE));
1663 static bool matches(
const Stmt *S, ASTContext &Ctx,
1664 const UnsafeBufferUsageHandler *Handler,
1671 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1672 bool IsRelatedToDecl,
1673 ASTContext &Ctx)
const override {
1676 SourceLocation getSourceLoc()
const override {
return Ctor->getBeginLoc(); }
1678 DeclUseList getClaimedVarUseSites()
const override {
1681 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->getArg(0))) {
1688 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1695class PointerInitGadget :
public FixableGadget {
1697 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1698 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1699 const VarDecl *PtrInitLHS;
1700 const DeclRefExpr *PtrInitRHS;
1704 : FixableGadget(
Kind::PointerInit),
1705 PtrInitLHS(
Result.getNodeAs<VarDecl>(PointerInitLHSTag)),
1706 PtrInitRHS(
Result.getNodeAs<DeclRefExpr>(PointerInitRHSTag)) {}
1708 static bool classof(
const Gadget *G) {
1709 return G->getKind() == Kind::PointerInit;
1712 static bool matches(
const Stmt *S,
1713 llvm::SmallVectorImpl<MatchResult> &Results) {
1714 const DeclStmt *DS = dyn_cast<DeclStmt>(S);
1723 const auto *DRE = dyn_cast<DeclRefExpr>(
Init->IgnoreImpCasts());
1724 if (!DRE || !
hasPointerType(*DRE) || !isSupportedVariable(*DRE)) {
1728 R.addNode(PointerInitLHSTag, DynTypedNode::create(*VD));
1729 R.addNode(PointerInitRHSTag, DynTypedNode::create(*DRE));
1730 Results.emplace_back(std::move(R));
1734 virtual std::optional<FixItList>
1735 getFixits(
const FixitStrategy &S)
const override;
1736 SourceLocation getSourceLoc()
const override {
1737 return PtrInitRHS->getBeginLoc();
1740 virtual DeclUseList getClaimedVarUseSites()
const override {
1741 return DeclUseList{PtrInitRHS};
1744 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1745 getStrategyImplications()
const override {
1746 return std::make_pair(PtrInitLHS,
cast<VarDecl>(PtrInitRHS->getDecl()));
1755class PtrToPtrAssignmentGadget :
public FixableGadget {
1757 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1758 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1759 const DeclRefExpr *PtrLHS;
1760 const DeclRefExpr *PtrRHS;
1764 : FixableGadget(
Kind::PtrToPtrAssignment),
1765 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1766 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1768 static bool classof(
const Gadget *G) {
1769 return G->getKind() == Kind::PtrToPtrAssignment;
1772 static bool matches(
const Stmt *S,
1773 llvm::SmallVectorImpl<MatchResult> &Results) {
1774 size_t SizeBefore = Results.size();
1776 const auto *BO = dyn_cast<BinaryOperator>(S);
1777 if (!BO || BO->
getOpcode() != BO_Assign)
1780 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1782 !isSupportedVariable(*RHSRef)) {
1785 const auto *LHS = BO->
getLHS();
1786 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1788 !isSupportedVariable(*LHSRef)) {
1792 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1793 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1794 Results.emplace_back(std::move(R));
1796 return SizeBefore != Results.size();
1799 virtual std::optional<FixItList>
1800 getFixits(
const FixitStrategy &S)
const override;
1801 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1803 virtual DeclUseList getClaimedVarUseSites()
const override {
1804 return DeclUseList{PtrLHS, PtrRHS};
1807 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1808 getStrategyImplications()
const override {
1819class CArrayToPtrAssignmentGadget :
public FixableGadget {
1821 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1822 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1823 const DeclRefExpr *PtrLHS;
1824 const DeclRefExpr *PtrRHS;
1828 : FixableGadget(
Kind::CArrayToPtrAssignment),
1829 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1830 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1832 static bool classof(
const Gadget *G) {
1833 return G->getKind() == Kind::CArrayToPtrAssignment;
1836 static bool matches(
const Stmt *S,
1837 llvm::SmallVectorImpl<MatchResult> &Results) {
1838 size_t SizeBefore = Results.size();
1840 const auto *BO = dyn_cast<BinaryOperator>(S);
1841 if (!BO || BO->
getOpcode() != BO_Assign)
1844 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1847 !isSupportedVariable(*RHSRef)) {
1850 const auto *LHS = BO->
getLHS();
1851 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1853 !isSupportedVariable(*LHSRef)) {
1857 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1858 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1859 Results.emplace_back(std::move(R));
1861 return SizeBefore != Results.size();
1864 virtual std::optional<FixItList>
1865 getFixits(
const FixitStrategy &S)
const override;
1866 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1868 virtual DeclUseList getClaimedVarUseSites()
const override {
1869 return DeclUseList{PtrLHS, PtrRHS};
1872 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1873 getStrategyImplications()
const override {
1880class UnsafeBufferUsageAttrGadget :
public WarningGadget {
1881 constexpr static const char *
const OpTag =
"attr_expr";
1886 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
1887 Op(
Result.getNodeAs<Expr>(OpTag)) {}
1889 static bool classof(
const Gadget *G) {
1890 return G->getKind() == Kind::UnsafeBufferUsageAttr;
1893 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1895 if (
auto *CE = dyn_cast<CallExpr>(S)) {
1896 if (CE->getDirectCallee() &&
1897 CE->getDirectCallee()->hasAttr<UnsafeBufferUsageAttr>()) {
1898 Result.addNode(OpTag, DynTypedNode::create(*CE));
1902 if (
auto *ME = dyn_cast<MemberExpr>(S)) {
1905 if (ME->getMemberDecl()->hasAttr<UnsafeBufferUsageAttr>()) {
1906 Result.addNode(OpTag, DynTypedNode::create(*ME));
1913 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1914 bool IsRelatedToDecl,
1915 ASTContext &Ctx)
const override {
1918 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1920 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1922 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1928class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
1929 constexpr static const char *
const OpTag =
"cxx_construct_expr";
1930 const CXXConstructExpr *Op;
1934 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
1935 Op(
Result.getNodeAs<CXXConstructExpr>(OpTag)) {}
1937 static bool classof(
const Gadget *G) {
1938 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
1942 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1943 if (!CE || !CE->getConstructor()->hasAttr<UnsafeBufferUsageAttr>())
1947 if (SpanTwoParamConstructorGadget::matches(CE, Ctx, Tmp))
1949 Result.addNode(OpTag, DynTypedNode::create(*CE));
1953 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1954 bool IsRelatedToDecl,
1955 ASTContext &Ctx)
const override {
1958 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1960 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1962 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1969class DataInvocationGadget :
public WarningGadget {
1970 constexpr static const char *
const OpTag =
"data_invocation_expr";
1971 const ExplicitCastExpr *Op;
1975 : WarningGadget(
Kind::DataInvocation),
1976 Op(
Result.getNodeAs<ExplicitCastExpr>(OpTag)) {}
1978 static bool classof(
const Gadget *G) {
1979 return G->getKind() == Kind::DataInvocation;
1982 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1984 auto *CE = dyn_cast<ExplicitCastExpr>(S);
1987 for (
auto *Child : CE->children()) {
1988 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Child);
1989 MCE && isDataFunction(MCE)) {
1990 Result.addNode(OpTag, DynTypedNode::create(*CE));
1993 if (
auto *
Paren = dyn_cast<ParenExpr>(Child)) {
1994 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(
Paren->getSubExpr());
1995 MCE && isDataFunction(MCE)) {
1996 Result.addNode(OpTag, DynTypedNode::create(*CE));
2004 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2005 bool IsRelatedToDecl,
2006 ASTContext &Ctx)
const override {
2009 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2011 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2014 static bool isDataFunction(
const CXXMemberCallExpr *call) {
2021 if (method->getNameAsString() ==
"data" &&
2022 method->getParent()->isInStdNamespace() &&
2023 llvm::is_contained({SIZED_CONTAINER_OR_VIEW_LIST},
2024 method->getParent()->getName()))
2029 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2032class UnsafeLibcFunctionCallGadget :
public WarningGadget {
2033 const CallExpr *
const Call;
2034 const Expr *UnsafeArg =
nullptr;
2035 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
2037 constexpr static const char *
const UnsafeSprintfTag =
2038 "UnsafeLibcFunctionCall_sprintf";
2039 constexpr static const char *
const UnsafeSizedByTag =
2040 "UnsafeLibcFunctionCall_sized_by";
2041 constexpr static const char *
const UnsafeStringTag =
2042 "UnsafeLibcFunctionCall_string";
2043 constexpr static const char *
const UnsafeVaListTag =
2044 "UnsafeLibcFunctionCall_va_list";
2056 } WarnedFunKind = OTHERS;
2060 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2061 Call(
Result.getNodeAs<CallExpr>(Tag)) {
2062 if (
Result.getNodeAs<Decl>(UnsafeSprintfTag))
2063 WarnedFunKind = SPRINTF;
2064 else if (
auto *E =
Result.getNodeAs<Expr>(UnsafeStringTag)) {
2065 WarnedFunKind = STRING;
2067 }
else if (
Result.getNodeAs<CallExpr>(UnsafeSizedByTag)) {
2068 WarnedFunKind = SIZED_BY;
2069 UnsafeArg = Call->getArg(0);
2070 }
else if (
Result.getNodeAs<Decl>(UnsafeVaListTag))
2071 WarnedFunKind = VA_LIST;
2074 static bool matches(
const Stmt *S, ASTContext &Ctx,
2075 const UnsafeBufferUsageHandler *Handler,
2079 auto *CE = dyn_cast<CallExpr>(S);
2080 if (!CE || !CE->getDirectCallee())
2082 const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
2086 bool IsGlobalAndNotInAnyNamespace =
2087 FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
2091 if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
2093 auto isSingleStringLiteralArg =
false;
2094 if (CE->getNumArgs() == 1) {
2095 isSingleStringLiteralArg =
2098 if (!isSingleStringLiteralArg) {
2101 Result.addNode(Tag, DynTypedNode::create(*CE));
2105 Result.addNode(Tag, DynTypedNode::create(*CE));
2106 Result.addNode(UnsafeVaListTag, DynTypedNode::create(*FD));
2110 Result.addNode(Tag, DynTypedNode::create(*CE));
2111 Result.addNode(UnsafeSprintfTag, DynTypedNode::create(*FD));
2117 Result.addNode(Tag, DynTypedNode::create(*CE));
2118 Result.addNode(UnsafeSizedByTag, DynTypedNode::create(*CE));
2123 Result.addNode(Tag, DynTypedNode::create(*CE));
2130 const Stmt *getBaseStmt()
const {
return Call; }
2132 SourceLocation getSourceLoc()
const override {
return Call->getBeginLoc(); }
2134 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2135 bool IsRelatedToDecl,
2136 ASTContext &Ctx)
const override {
2140 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2142 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2148class ULCArraySubscriptGadget :
public FixableGadget {
2150 static constexpr const char *
const ULCArraySubscriptTag =
2151 "ArraySubscriptUnderULC";
2152 const ArraySubscriptExpr *Node;
2156 : FixableGadget(
Kind::ULCArraySubscript),
2157 Node(
Result.getNodeAs<ArraySubscriptExpr>(ULCArraySubscriptTag)) {
2158 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2161 static bool classof(
const Gadget *G) {
2162 return G->getKind() == Kind::ULCArraySubscript;
2165 static bool matches(
const Stmt *S,
2166 llvm::SmallVectorImpl<MatchResult> &Results) {
2167 size_t SizeBefore = Results.size();
2169 const auto *ASE = dyn_cast<ArraySubscriptExpr>(E);
2175 !isSupportedVariable(*DRE))
2178 R.addNode(ULCArraySubscriptTag, DynTypedNode::create(*ASE));
2179 Results.emplace_back(std::move(R));
2181 return SizeBefore != Results.size();
2184 virtual std::optional<FixItList>
2185 getFixits(
const FixitStrategy &S)
const override;
2186 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2188 virtual DeclUseList getClaimedVarUseSites()
const override {
2189 if (
const auto *DRE =
2190 dyn_cast<DeclRefExpr>(Node->getBase()->IgnoreImpCasts())) {
2200class UPCStandalonePointerGadget :
public FixableGadget {
2202 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
2203 const DeclRefExpr *Node;
2207 : FixableGadget(
Kind::UPCStandalonePointer),
2208 Node(
Result.getNodeAs<DeclRefExpr>(DeclRefExprTag)) {
2209 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2212 static bool classof(
const Gadget *G) {
2213 return G->getKind() == Kind::UPCStandalonePointer;
2216 static bool matches(
const Stmt *S,
2217 llvm::SmallVectorImpl<MatchResult> &Results) {
2218 size_t SizeBefore = Results.size();
2220 auto *E = dyn_cast<Expr>(S);
2225 !isSupportedVariable(*DRE))
2228 R.addNode(DeclRefExprTag, DynTypedNode::create(*DRE));
2229 Results.emplace_back(std::move(R));
2231 return SizeBefore != Results.size();
2234 virtual std::optional<FixItList>
2235 getFixits(
const FixitStrategy &S)
const override;
2236 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2238 virtual DeclUseList getClaimedVarUseSites()
const override {
return {Node}; }
2241class PointerDereferenceGadget :
public FixableGadget {
2242 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2243 static constexpr const char *
const OperatorTag =
"op";
2245 const DeclRefExpr *BaseDeclRefExpr =
nullptr;
2246 const UnaryOperator *Op =
nullptr;
2250 : FixableGadget(
Kind::PointerDereference),
2251 BaseDeclRefExpr(
Result.getNodeAs<DeclRefExpr>(BaseDeclRefExprTag)),
2252 Op(
Result.getNodeAs<UnaryOperator>(OperatorTag)) {}
2254 static bool classof(
const Gadget *G) {
2255 return G->getKind() == Kind::PointerDereference;
2258 static bool matches(
const Stmt *S,
2259 llvm::SmallVectorImpl<MatchResult> &Results) {
2260 size_t SizeBefore = Results.size();
2262 const auto *UO = dyn_cast<UnaryOperator>(S);
2265 const auto *CE = dyn_cast<Expr>(UO->
getSubExpr());
2268 CE = CE->IgnoreParenImpCasts();
2269 const auto *DRE = dyn_cast<DeclRefExpr>(CE);
2270 if (!DRE || !isSupportedVariable(*DRE))
2273 R.addNode(BaseDeclRefExprTag, DynTypedNode::create(*DRE));
2274 R.addNode(OperatorTag, DynTypedNode::create(*UO));
2275 Results.emplace_back(std::move(R));
2277 return SizeBefore != Results.size();
2280 DeclUseList getClaimedVarUseSites()
const override {
2281 return {BaseDeclRefExpr};
2284 virtual std::optional<FixItList>
2285 getFixits(
const FixitStrategy &S)
const override;
2286 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2292class UPCAddressofArraySubscriptGadget :
public FixableGadget {
2294 static constexpr const char *
const UPCAddressofArraySubscriptTag =
2295 "AddressofArraySubscriptUnderUPC";
2296 const UnaryOperator *Node;
2300 : FixableGadget(
Kind::ULCArraySubscript),
2301 Node(
Result.getNodeAs<UnaryOperator>(UPCAddressofArraySubscriptTag)) {
2302 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2305 static bool classof(
const Gadget *G) {
2306 return G->getKind() == Kind::UPCAddressofArraySubscript;
2309 static bool matches(
const Stmt *S,
2310 llvm::SmallVectorImpl<MatchResult> &Results) {
2311 size_t SizeBefore = Results.size();
2313 auto *E = dyn_cast<Expr>(S);
2317 if (!UO || UO->
getOpcode() != UO_AddrOf)
2319 const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->
getSubExpr());
2324 if (!DRE || !isSupportedVariable(*DRE))
2327 R.addNode(UPCAddressofArraySubscriptTag, DynTypedNode::create(*UO));
2328 Results.emplace_back(std::move(R));
2330 return SizeBefore != Results.size();
2333 virtual std::optional<FixItList>
2334 getFixits(
const FixitStrategy &)
const override;
2335 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2337 virtual DeclUseList getClaimedVarUseSites()
const override {
2350class DeclUseTracker {
2351 using UseSetTy = llvm::SmallPtrSet<const DeclRefExpr *, 16>;
2352 using DefMapTy = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
2355 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
2359 DeclUseTracker() =
default;
2360 DeclUseTracker(
const DeclUseTracker &) =
delete;
2361 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
2362 DeclUseTracker(DeclUseTracker &&) =
default;
2363 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
2366 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
2369 void claimUse(
const DeclRefExpr *DRE) {
2370 assert(Uses->count(DRE) &&
2371 "DRE not found or claimed by multiple matchers!");
2376 bool hasUnclaimedUses(
const VarDecl *VD)
const {
2378 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
2383 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
2385 for (
auto use : *Uses) {
2387 ReturnSet.insert(use);
2393 void discoverDecl(
const DeclStmt *DS) {
2394 for (
const Decl *D : DS->
decls()) {
2395 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
2406 const DeclStmt *lookupDecl(
const VarDecl *VD)
const {
2407 return Defs.lookup(VD);
2416 static constexpr const char *
const UPCPreIncrementTag =
2417 "PointerPreIncrementUnderUPC";
2422 : FixableGadget(Kind::UPCPreIncrement),
2424 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2428 return G->getKind() == Kind::UPCPreIncrement;
2437 size_t SizeBefore = Results.size();
2439 auto *E = dyn_cast<Expr>(S);
2443 if (!UO || UO->
getOpcode() != UO_PreInc)
2445 const auto *DRE = dyn_cast<DeclRefExpr>(UO->
getSubExpr());
2446 if (!DRE || !isSupportedVariable(*DRE))
2450 Results.emplace_back(std::move(R));
2452 return SizeBefore != Results.size();
2455 virtual std::optional<FixItList>
2460 return {dyn_cast<DeclRefExpr>(Node->getSubExpr())};
2468 static constexpr const char *
const UUCAddAssignTag =
2469 "PointerAddAssignUnderUUC";
2470 static constexpr const char *
const OffsetTag =
"Offset";
2473 const Expr *Offset =
nullptr;
2477 : FixableGadget(Kind::UUCAddAssign),
2480 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2484 return G->getKind() == Kind::UUCAddAssign;
2489 size_t SizeBefore = Results.size();
2491 const auto *E = dyn_cast<Expr>(S);
2495 if (!BO || BO->
getOpcode() != BO_AddAssign)
2497 const auto *DRE = dyn_cast<DeclRefExpr>(BO->
getLHS());
2503 Results.emplace_back(std::move(R));
2505 return SizeBefore != Results.size();
2508 virtual std::optional<FixItList>
2513 return {dyn_cast<DeclRefExpr>(Node->getLHS())};
2520 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2521 static constexpr const char *
const DerefOpTag =
"DerefOp";
2522 static constexpr const char *
const AddOpTag =
"AddOp";
2523 static constexpr const char *
const OffsetTag =
"Offset";
2532 : FixableGadget(Kind::DerefSimplePtrArithFixable),
2540 auto IsPtr = [](
const Expr *E, MatchResult &R) {
2544 if (!DRE || !isSupportedVariable(*DRE))
2549 const auto IsPlusOverPtrAndInteger = [&IsPtr](
const Expr *E,
2551 const auto *BO = dyn_cast<BinaryOperator>(E);
2555 const auto *LHS = BO->
getLHS();
2556 const auto *RHS = BO->
getRHS();
2569 size_t SizeBefore = Results.size();
2570 const auto InnerMatcher = [&IsPlusOverPtrAndInteger,
2571 &Results](
const Expr *E) {
2572 const auto *UO = dyn_cast<UnaryOperator>(E);
2578 if (IsPlusOverPtrAndInteger(Operand, R)) {
2580 Results.emplace_back(std::move(R));
2584 return SizeBefore != Results.size();
2587 virtual std::optional<FixItList>
2590 return DerefOp->getBeginLoc();
2594 return {BaseDeclRefExpr};
2602 : WarningGadgets(WarningGadgets) {}
2611#define WARNING_GADGET(name) \
2612 if (name##Gadget::matches(S, Ctx, Result) && \
2613 notInSafeBufferOptOut(*S, &Handler)) { \
2614 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2617#define WARNING_OPTIONAL_GADGET(name) \
2618 if (name##Gadget::matches(S, Ctx, &Handler, Result) && \
2619 notInSafeBufferOptOut(*S, &Handler)) { \
2620 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2623#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2628 WarningGadgetList &WarningGadgets;
2635 DeclUseTracker &Tracker)
2636 : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
2640 bool matchFound =
false;
2647#define FIXABLE_GADGET(name) \
2648 if (name##Gadget::matches(S, Results)) { \
2649 for (const auto &R : Results) { \
2650 FixableGadgets.push_back(std::make_unique<name##Gadget>(R)); \
2651 matchFound = true; \
2655#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2658 if (
auto *DRE = findDeclRefExpr(S); DRE) {
2659 Tracker.discoverUse(DRE);
2665 if (
auto *DS = findDeclStmt(S); DS) {
2666 Tracker.discoverDecl(DS);
2674 const auto *DRE = dyn_cast<DeclRefExpr>(S);
2682 const DeclStmt *findDeclStmt(
const Stmt *S) {
2683 const auto *DS = dyn_cast<DeclStmt>(S);
2688 FixableGadgetList &FixableGadgets;
2689 DeclUseTracker &Tracker;
2695 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2696 WarningGadgetList &WarningGadgets,
2697 DeclUseTracker &Tracker) {
2700 if (EmitSuggestions) {
2709 return N1->getBeginLoc().getRawEncoding() <
2710 N2->getBeginLoc().getRawEncoding();
2720 const Expr *UnsafeArg =
nullptr)
override {}
2728 bool IsRelatedToDecl,
2745 FixableGadgetList FixableGadgets;
2746 WarningGadgetList WarningGadgets;
2747 DeclUseTracker Tracker;
2748 MockReporter IgnoreHandler;
2751 FixableGadgets, WarningGadgets, Tracker);
2753 std::set<const Expr *>
Result;
2754 for (
auto &G : WarningGadgets) {
2755 for (
const Expr *E : G->getUnsafePtrs()) {
2764 std::map<const VarDecl *, std::set<const WarningGadget *>,
2778 for (
auto &G : AllUnsafeOperations) {
2779 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
2781 bool AssociatedWithVarDecl =
false;
2782 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
2783 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2784 result.
byVar[VD].insert(G.get());
2785 AssociatedWithVarDecl =
true;
2789 if (!AssociatedWithVarDecl) {
2790 result.
noVar.push_back(G.get());
2798 std::map<const VarDecl *, std::set<const FixableGadget *>,
2808 for (
auto &F : AllFixableOperations) {
2809 DeclUseList DREs = F->getClaimedVarUseSites();
2812 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2813 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
2817 return FixablesForUnsafeVars;
2824 std::vector<const FixItHint *>
All;
2828 std::sort(
All.begin(),
All.end(),
2830 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
2831 H2->RemoveRange.getBegin());
2839 Hint->RemoveRange.getBegin())) {
2851std::optional<FixItList>
2852PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2855 switch (S.
lookup(LeftVD)) {
2859 return std::nullopt;
2861 return std::nullopt;
2864 return std::nullopt;
2866 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2868 return std::nullopt;
2872static inline std::optional<FixItList>
createDataFixit(
const ASTContext &Ctx,
2873 const DeclRefExpr *DRE);
2875std::optional<FixItList>
2876CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2895 if (S.
lookup(LeftVD) == FixitStrategy::Kind::Span) {
2896 if (S.
lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
2899 }
else if (S.
lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
2900 if (S.
lookup(RightVD) == FixitStrategy::Kind::Array) {
2904 return std::nullopt;
2907std::optional<FixItList>
2908PointerInitGadget::getFixits(
const FixitStrategy &S)
const {
2909 const auto *LeftVD = PtrInitLHS;
2911 switch (S.
lookup(LeftVD)) {
2912 case FixitStrategy::Kind::Span:
2913 if (S.
lookup(RightVD) == FixitStrategy::Kind::Span)
2915 return std::nullopt;
2916 case FixitStrategy::Kind::Wontfix:
2917 return std::nullopt;
2918 case FixitStrategy::Kind::Iterator:
2919 case FixitStrategy::Kind::Array:
2920 return std::nullopt;
2921 case FixitStrategy::Kind::Vector:
2922 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2924 return std::nullopt;
2930 if (ConstVal->isNegative())
2937std::optional<FixItList>
2938ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2939 if (
const auto *DRE =
2941 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2943 case FixitStrategy::Kind::Span: {
2947 const ASTContext &Ctx =
2950 return std::nullopt;
2954 case FixitStrategy::Kind::Array:
2956 case FixitStrategy::Kind::Wontfix:
2957 case FixitStrategy::Kind::Iterator:
2958 case FixitStrategy::Kind::Vector:
2959 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2962 return std::nullopt;
2965static std::optional<FixItList>
2968std::optional<FixItList>
2969UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2970 auto DREs = getClaimedVarUseSites();
2974 case FixitStrategy::Kind::Span:
2976 case FixitStrategy::Kind::Wontfix:
2977 case FixitStrategy::Kind::Iterator:
2978 case FixitStrategy::Kind::Array:
2979 return std::nullopt;
2980 case FixitStrategy::Kind::Vector:
2981 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2983 return std::nullopt;
2988 static const char *
const EOL =
"\n";
2995 std::string
s = std::string(
"<# ");
2996 s += HintTextToUser;
3002template <
typename NodeTy>
3003static std::optional<SourceLocation>
3006 if (
unsigned TkLen =
3013 return std::nullopt;
3026 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
3027 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
3028 VD->getBeginLoc())) &&
3029 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
3030 At->getRange().getBegin()));
3034 AttrRangeOverlapping;
3076 std::optional<Qualifiers> Quals = std::nullopt) {
3077 const char *
const SpanOpen =
"std::span<";
3080 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
3081 return SpanOpen + EltTyText.str() +
'>';
3084std::optional<FixItList>
3086 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->getDecl());
3091 if (
auto ConstVal = Offset->getIntegerConstantExpr(Ctx))
3092 if (ConstVal->isNegative())
3093 return std::nullopt;
3114 const Expr *LHS = AddOp->getLHS(), *RHS = AddOp->getRHS();
3121 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
3123 return std::nullopt;
3128 std::optional<SourceLocation> AddOpLocation =
3130 std::optional<SourceLocation> DerefOpLocation =
3133 if (!AddOpLocation || !DerefOpLocation)
3134 return std::nullopt;
3144 return std::nullopt;
3147std::optional<FixItList>
3148PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
3159 if (
auto LocPastOperand =
3166 case FixitStrategy::Kind::Iterator:
3167 case FixitStrategy::Kind::Array:
3168 return std::nullopt;
3169 case FixitStrategy::Kind::Vector:
3170 llvm_unreachable(
"FixitStrategy not implemented yet!");
3171 case FixitStrategy::Kind::Wontfix:
3172 llvm_unreachable(
"Invalid strategy!");
3175 return std::nullopt;
3182 std::optional<SourceLocation> EndOfOperand =
3188 return std::nullopt;
3193std::optional<FixItList>
3194UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
3197 case FixitStrategy::Kind::Array:
3198 case FixitStrategy::Kind::Span: {
3203 case FixitStrategy::Kind::Wontfix:
3204 case FixitStrategy::Kind::Iterator:
3205 return std::nullopt;
3206 case FixitStrategy::Kind::Vector:
3207 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3210 return std::nullopt;
3215static std::optional<FixItList>
3222 const Expr *Idx = ArraySub->getIdx();
3225 std::stringstream SS;
3226 bool IdxIsLitZero =
false;
3229 if ((*ICE).isZero())
3230 IdxIsLitZero =
true;
3231 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
3233 return std::nullopt;
3237 SS << (*DreString).str() <<
".data()";
3239 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
3241 return std::nullopt;
3243 SS <<
"&" << (*DreString).str() <<
".data()"
3244 <<
"[" << (*IndexString).str() <<
"]";
3250std::optional<FixItList>
3254 if (DREs.size() != 1)
3255 return std::nullopt;
3257 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3261 const Stmt *AddAssignNode = Node;
3262 StringRef varName = VD->
getName();
3266 return std::nullopt;
3270 (Offset->IgnoreParens()->getBeginLoc() == Offset->getBeginLoc());
3271 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
3275 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
3277 if (!AddAssignLocation)
3278 return std::nullopt;
3285 Offset->getEndLoc().getLocWithOffset(1),
")"));
3289 return std::nullopt;
3292std::optional<FixItList>
3296 if (DREs.size() != 1)
3297 return std::nullopt;
3299 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3302 std::stringstream SS;
3303 StringRef varName = VD->
getName();
3307 SS <<
"(" << varName.data() <<
" = " << varName.data()
3308 <<
".subspan(1)).data()";
3309 std::optional<SourceLocation> PreIncLocation =
3311 if (!PreIncLocation)
3312 return std::nullopt;
3315 SourceRange(Node->getBeginLoc(), *PreIncLocation), SS.str()));
3319 return std::nullopt;
3337static std::optional<FixItList>
3339 const StringRef UserFillPlaceHolder) {
3347 if (
Init->isNullPointerConstant(
3352 NPC_ValueDependentIsNotNull)) {
3353 std::optional<SourceLocation> InitLocation =
3356 return std::nullopt;
3364 std::string ExtentText = UserFillPlaceHolder.data();
3365 StringRef One =
"1";
3370 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
3375 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
3376 if (!Ext->HasSideEffects(Ctx)) {
3377 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
3379 return std::nullopt;
3380 ExtentText = *ExtentString;
3382 }
else if (!CxxNew->isArray())
3394 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
3395 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
3396 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
3403 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
3406 return std::nullopt;
3408 StrBuffer.append(
", ");
3409 StrBuffer.append(ExtentText);
3410 StrBuffer.append(
"}");
3416#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
3417 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
3418 "failed to produce fixit for declaration '" + \
3419 (D)->getNameAsString() + "'" + (Msg))
3421#define DEBUG_NOTE_DECL_FAIL(D, Msg)
3427static std::optional<std::string>
3431 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3436 return std::nullopt;
3438 std::string SpanTyText =
"std::span<";
3440 SpanTyText.append(*PteTyText);
3442 if (PteTyQualifiers) {
3443 SpanTyText.append(
" ");
3444 SpanTyText.append(PteTyQualifiers->getAsString());
3446 SpanTyText.append(
">");
3465 const StringRef UserFillPlaceHolder,
3479 std::stringstream SS;
3484 std::optional<FixItList> InitFixIts =
3488 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
3489 std::make_move_iterator(InitFixIts->end()));
3496 if (!EndLocForReplacement.
isValid()) {
3546static std::optional<FixItList>
3552 return std::nullopt;
3557 std::vector<std::string> NewTysTexts(NumParms);
3558 std::vector<bool> ParmsMask(NumParms,
false);
3559 bool AtLeastOneParmToFix =
false;
3561 for (
unsigned i = 0; i < NumParms; i++) {
3568 return std::nullopt;
3570 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3571 std::optional<std::string> PteTyText =
3576 return std::nullopt;
3580 ParmsMask[i] =
true;
3581 AtLeastOneParmToFix =
true;
3583 if (!AtLeastOneParmToFix)
3590 const auto NewOverloadSignatureCreator =
3591 [&
SM, &LangOpts, &NewTysTexts,
3592 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3593 std::stringstream SS;
3601 SS << Prefix->str();
3603 return std::nullopt;
3607 for (
unsigned i = 0; i < NumParms; i++) {
3615 SS << NewTysTexts[i];
3618 SS <<
' ' << II->getName().str();
3619 }
else if (
auto ParmTypeText =
3623 SS << ParmTypeText->str();
3625 return std::nullopt;
3626 if (i != NumParms - 1)
3635 const auto OldOverloadDefCreator =
3636 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3637 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3638 std::stringstream SS;
3646 << FDPrefix->str() <<
"{";
3648 return std::nullopt;
3651 SS <<
"return " << FunQualName->str() <<
"(";
3653 return std::nullopt;
3657 for (
unsigned i = 0; i < NumParms; i++) {
3666 return std::nullopt;
3673 if (i != NumParms - 1)
3684 std::optional<SourceLocation> Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3688 if (FReDecl->isThisDeclarationADefinition()) {
3689 assert(FReDecl == FD &&
"inconsistent function definition");
3692 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3698 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3701 FReDecl->getBeginLoc(),
" ")));
3704 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3726 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3742 std::stringstream SS;
3745 if (PteTyQualifiers)
3754 SS <<
' ' << PVDNameText->str();
3760 const DeclUseTracker &Tracker,
3763 const DeclStmt *DS = Tracker.lookupDecl(VD);
3766 " : variables declared this way not implemented yet");
3790 const QualType &ArrayEltT = CAT->getElementType();
3791 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
3800 auto MaybeElemTypeTxt =
3803 if (!MaybeElemTypeTxt)
3805 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
3810 while (NextTok && !NextTok->is(tok::l_square) &&
3823 if (!MaybeArraySizeTxt)
3825 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
3826 if (ArraySizeTxt.empty()) {
3837 std::optional<StringRef> IdentText =
3846 llvm::raw_svector_ostream OS(Replacement);
3847 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
3848 << IdentText->str();
3858 const DeclUseTracker &Tracker,
3861 const DeclStmt *DS = Tracker.lookupDecl(VD);
3862 assert(DS &&
"Fixing non-local variables not implemented yet!");
3881 const DeclUseTracker &Tracker,
ASTContext &Ctx,
3883 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
3884 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
3885 if (!FD || FD != D) {
3896 if (FD->isMain() || FD->isConstexpr() ||
3903 FD->isOverloadedOperator()) {
3912 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
3930 llvm_unreachable(
"FixitStrategy not implemented yet!");
3932 llvm_unreachable(
"Invalid strategy!");
3934 llvm_unreachable(
"Unknown strategy!");
3942 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
3944 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
3961 std::map<const VarDecl *, FixItList> &FixItsForVariable,
3966 for (
const auto &[VD, Ignore] : FixItsForVariable) {
3968 if (llvm::any_of(Grp,
3969 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
3970 return !FixItsForVariable.count(GrpMember);
3975 ToErase.push_back(
Member);
3978 for (
auto *VarToErase : ToErase)
3979 FixItsForVariable.erase(VarToErase);
3990 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
3994 FixItList FixItsSharedByParms{};
3996 std::optional<FixItList> OverloadFixes =
3999 if (OverloadFixes) {
4000 FixItsSharedByParms.append(*OverloadFixes);
4006 FixItsForVariable.erase(
Member);
4008 return FixItsSharedByParms;
4012static std::map<const VarDecl *, FixItList>
4021 std::map<const VarDecl *, FixItList> FixItsForVariable;
4026 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
4027 FixItsForVariable[VD] =
4031 if (FixItsForVariable[VD].empty()) {
4032 FixItsForVariable.erase(VD);
4035 for (
const auto &F : Fixables) {
4036 std::optional<FixItList> Fixits = F->getFixits(S);
4039 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
4040 Fixits->begin(), Fixits->end());
4045 VD, F->getSourceLoc(),
4046 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
4049 FixItsForVariable.erase(VD);
4068 FixItList FixItsSharedByParms{};
4070 if (
auto *FD = dyn_cast<FunctionDecl>(D))
4072 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
4076 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
4079 for (
auto &[Var, Ignore] : FixItsForVariable) {
4080 bool AnyParm =
false;
4081 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
4083 for (
const VarDecl *GrpMate : VarGroupForVD) {
4086 if (FixItsForVariable.count(GrpMate))
4087 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
4091 assert(!FixItsSharedByParms.empty() &&
4092 "Should not try to fix a parameter that does not belong to a "
4094 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
4101 for (
auto Iter = FinalFixItsForVariable.begin();
4102 Iter != FinalFixItsForVariable.end();)
4105 Iter = FinalFixItsForVariable.erase(Iter);
4108 return FinalFixItsForVariable;
4111template <
typename VarDeclIterTy>
4115 for (
const VarDecl *VD : UnsafeVars) {
4126 const std::vector<VarGrpTy> Groups;
4127 const std::map<const VarDecl *, unsigned> &VarGrpMap;
4128 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
4132 const std::vector<VarGrpTy> &Groups,
4133 const std::map<const VarDecl *, unsigned> &VarGrpMap,
4134 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
4135 : Groups(Groups), VarGrpMap(VarGrpMap),
4136 GrpsUnionForParms(GrpsUnionForParms) {}
4139 if (GrpsUnionForParms.contains(Var)) {
4142 return GrpsUnionForParms.getArrayRef();
4147 auto It = VarGrpMap.find(Var);
4149 if (It == VarGrpMap.end())
4151 return Groups[It->second];
4155 return GrpsUnionForParms.getArrayRef();
4160 WarningGadgetList WarningGadgets,
4161 DeclUseTracker Tracker,
4163 bool EmitSuggestions) {
4164 if (!EmitSuggestions) {
4168 for (
const auto &G : WarningGadgets) {
4169 G->handleUnsafeOperation(Handler,
false,
4175 assert(FixableGadgets.empty() &&
4176 "Fixable gadgets found but suggestions not requested!");
4182 if (!WarningGadgets.empty()) {
4186 for (
const auto &G : FixableGadgets) {
4187 for (
const auto *DRE : G->getClaimedVarUseSites()) {
4188 Tracker.claimUse(DRE);
4204 if (WarningGadgets.empty())
4212 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
4215 for (
auto it = FixablesForAllVars.
byVar.cbegin();
4216 it != FixablesForAllVars.
byVar.cend();) {
4221 (
"failed to produce fixit for '" +
4222 it->first->getNameAsString() +
4223 "' : neither local nor a parameter"));
4225 it = FixablesForAllVars.
byVar.erase(it);
4226 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
4229 (
"failed to produce fixit for '" +
4230 it->first->getNameAsString() +
4231 "' : has a reference type"));
4233 it = FixablesForAllVars.
byVar.erase(it);
4234 }
else if (Tracker.hasUnclaimedUses(it->first)) {
4235 it = FixablesForAllVars.
byVar.erase(it);
4236 }
else if (it->first->isInitCapture()) {
4239 (
"failed to produce fixit for '" +
4240 it->first->getNameAsString() +
4241 "' : init capture"));
4243 it = FixablesForAllVars.
byVar.erase(it);
4250 for (
const auto &it : UnsafeOps.
byVar) {
4251 const VarDecl *
const UnsafeVD = it.first;
4252 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
4253 if (UnclaimedDREs.empty())
4257 std::string UnclaimedUseTrace =
4262 (
"failed to produce fixit for '" + UnfixedVDName +
4263 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
4264 UnclaimedUseTrace));
4271 llvm::DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
4272 DepMapTy DependenciesMap{};
4273 DepMapTy PtrAssignmentGraph{};
4275 for (
const auto &it : FixablesForAllVars.
byVar) {
4276 for (
const FixableGadget *fixable : it.second) {
4277 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
4278 fixable->getStrategyImplications();
4280 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
4281 PtrAssignmentGraph[Impl.first].insert(Impl.second);
4303 std::set<const VarDecl *> VisitedVarsDirected{};
4304 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4305 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
4307 std::queue<const VarDecl *> QueueDirected{};
4308 QueueDirected.push(Var);
4309 while (!QueueDirected.empty()) {
4310 const VarDecl *CurrentVar = QueueDirected.front();
4311 QueueDirected.pop();
4312 VisitedVarsDirected.insert(CurrentVar);
4313 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
4314 for (
const VarDecl *Adj : AdjacentNodes) {
4315 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
4316 QueueDirected.push(Adj);
4318 DependenciesMap[Var].insert(Adj);
4319 DependenciesMap[Adj].insert(Var);
4326 std::vector<VarGrpTy> Groups;
4330 std::map<const VarDecl *, unsigned> VarGrpMap;
4332 llvm::SetVector<const VarDecl *>
4337 std::set<const VarDecl *> VisitedVars{};
4338 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4339 if (VisitedVars.find(Var) == VisitedVars.end()) {
4340 VarGrpTy &VarGroup = Groups.emplace_back();
4341 std::queue<const VarDecl *> Queue{};
4344 while (!Queue.empty()) {
4345 const VarDecl *CurrentVar = Queue.front();
4347 VisitedVars.insert(CurrentVar);
4348 VarGroup.push_back(CurrentVar);
4349 auto AdjacentNodes = DependenciesMap[CurrentVar];
4350 for (
const VarDecl *Adj : AdjacentNodes) {
4351 if (VisitedVars.find(Adj) == VisitedVars.end()) {
4357 bool HasParm =
false;
4358 unsigned GrpIdx = Groups.size() - 1;
4360 for (
const VarDecl *
V : VarGroup) {
4361 VarGrpMap[
V] = GrpIdx;
4366 GrpsUnionForParms.insert_range(VarGroup);
4388 for (
auto I = FixablesForAllVars.
byVar.begin();
4389 I != FixablesForAllVars.
byVar.end();) {
4391 if (!VisitedVars.count((*I).first)) {
4393 I = FixablesForAllVars.
byVar.erase(I);
4401 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
4403 return FixablesForAllVars.
byVar.count(
V);
4410 FixItsForVariableGroup =
4412 Tracker, Handler, VarGrpMgr);
4414 for (
const auto &G : UnsafeOps.
noVar) {
4415 G->handleUnsafeOperation(Handler,
false,
4419 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
4420 auto FixItsIt = FixItsForVariableGroup.find(VD);
4422 FixItsIt != FixItsForVariableGroup.end()
4423 ? std::move(FixItsIt->second)
4426 for (
const auto &G : WarningGadgets) {
4427 G->handleUnsafeOperation(Handler,
true,
4435 bool EmitSuggestions) {
4444 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
4448 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
4449 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
4454 if (FReDecl->isExternC()) {
4457 EmitSuggestions =
false;
4462 Stmts.push_back(FD->getBody());
4464 if (
const auto *ID = dyn_cast<CXXConstructorDecl>(D)) {
4466 Stmts.push_back(CI->getInit());
4470 Stmts.push_back(D->
getBody());
4473 assert(!Stmts.empty());
4475 FixableGadgetList FixableGadgets;
4476 WarningGadgetList WarningGadgets;
4477 DeclUseTracker Tracker;
4478 for (
Stmt *S : Stmts) {
4480 WarningGadgets, Tracker);
4482 applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
4483 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 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)
#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 isNullTermPointer(const Expr *Ptr)
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)