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 );
832 const Expr *&UnsafeArg,
const unsigned FmtIdx,
833 std::optional<const unsigned> FmtArgIdx = std::nullopt,
834 bool isKprintf =
false) {
835 class StringFormatStringHandler
839 const Expr *&UnsafeArg;
855 unsigned PArgIdx = Precision.
getArgIndex() + FmtArgIdx;
857 if (PArgIdx < Call->getNumArgs()) {
858 const Expr *PArg =
Call->getArg(PArgIdx);
861 if (
auto *CE = dyn_cast<CastExpr>(PArg);
862 CE && CE->getType()->isSignedIntegerType())
863 PArg = CE->getSubExpr();
868 analyze_printf::OptionalAmount::HowSpecified::Constant) {
870 llvm::APSInt PArgVal = llvm::APSInt(
880 StringFormatStringHandler(
const CallExpr *
Call,
unsigned FmtArgIdx,
882 :
Call(
Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx),
883 UnsafeArgSet(
false) {}
886 const char *startSpecifier,
887 unsigned specifierLen,
895 if (ArgIdx >=
Call->getNumArgs())
899 const Expr *Arg =
Call->getArg(ArgIdx);
909 bool IsArgTypeValid =
912 ?
ArgType->getPointeeType()->isWideCharType()
913 :
ArgType->getPointeeType()->isCharType());
916 Precision && IsArgTypeValid)
920 UnsafeArg =
Call->getArg(ArgIdx);
925 bool isUnsafeArgSet() {
return UnsafeArgSet; }
928 const Expr *Fmt =
Call->getArg(FmtIdx);
929 unsigned FmtArgStartingIdx =
930 FmtArgIdx.has_value() ?
static_cast<unsigned>(*FmtArgIdx) : FmtIdx + 1;
933 if (SL->getCharByteWidth() == 1) {
934 StringRef FmtStr = SL->getString();
935 StringFormatStringHandler Handler(
Call, FmtArgStartingIdx, UnsafeArg,
939 Handler, FmtStr.begin(), FmtStr.end(), Ctx.
getLangOpts(),
941 Handler.isUnsafeArgSet();
944 if (
auto FmtStr = SL->tryEvaluateString(Ctx)) {
945 StringFormatStringHandler Handler(
Call, FmtArgStartingIdx, UnsafeArg,
948 Handler, FmtStr->data(), FmtStr->data() + FmtStr->size(),
950 Handler.isUnsafeArgSet();
957 llvm::make_range(
Call->arg_begin() + FmtIdx,
Call->arg_end()),
958 [&UnsafeArg, &Ctx](
const Expr *Arg) ->
bool {
959 if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg, Ctx)) {
977 static std::unique_ptr<std::set<StringRef>> PredefinedNames =
nullptr;
978 if (!PredefinedNames)
980 std::make_unique<std::set<StringRef>, std::set<StringRef>>({
1061 if (PredefinedNames->find(Name) != PredefinedNames->end())
1064 std::string NameWCS = Name.str();
1065 size_t WcsPos = NameWCS.find(
"wcs");
1067 while (WcsPos != std::string::npos) {
1068 NameWCS[WcsPos++] =
's';
1069 NameWCS[WcsPos++] =
't';
1070 NameWCS[WcsPos++] =
'r';
1071 WcsPos = NameWCS.find(
"wcs", WcsPos);
1073 if (PredefinedNames->find(NameWCS) != PredefinedNames->end())
1077 return Name.ends_with(
"scanf");
1092 if (!Name.ends_with(
"printf"))
1094 return Name.starts_with(
"v");
1108 if (!Name.ends_with(
"printf") ||
1110 Name.starts_with(
"v"))
1113 StringRef Prefix = Name.drop_back(6);
1115 if (Prefix.ends_with(
"w"))
1116 Prefix = Prefix.drop_back(1);
1117 return Prefix ==
"s";
1132 if (!Name.ends_with(
"printf") || Name.starts_with(
"v"))
1135 StringRef Prefix = Name.drop_back(6);
1137 if (Prefix.ends_with(
"w"))
1138 Prefix = Prefix.drop_back(1);
1140 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
1148 MatchResult &Result, llvm::StringRef Tag) {
1152 assert(FD &&
"It should have been checked that FD is non-null.");
1170 const Expr *UnsafeArg;
1181 bool isKprintf =
false;
1182 const Expr *UnsafeArg;
1185 isKprintf = II->getName() ==
"kprintf";
1187 std::nullopt, isKprintf)) {
1200 const Expr *UnsafeArg;
1211 for (
const auto *Arg : Node.
arguments())
1226 assert(FD &&
"It should have been checked that FD is non-null.");
1241 !Size->getType()->isUnsignedIntegerType())
1270#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1273 Gadget(Kind K) : K(K) {}
1275 Kind
getKind()
const {
return K; }
1278 StringRef getDebugName()
const {
1283#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1285 llvm_unreachable(
"Unhandled Gadget::Kind enum");
1289 virtual bool isWarningGadget()
const = 0;
1292 virtual SourceLocation getSourceLoc()
const = 0;
1297 virtual DeclUseList getClaimedVarUseSites()
const = 0;
1299 virtual ~Gadget() =
default;
1307class WarningGadget :
public Gadget {
1309 WarningGadget(Kind K) : Gadget(K) {}
1311 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1312 bool isWarningGadget() const final {
return true; }
1314 virtual void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1315 bool IsRelatedToDecl,
1316 ASTContext &Ctx)
const = 0;
1318 virtual SmallVector<const Expr *, 1> getUnsafePtrs()
const = 0;
1325class FixableGadget :
public Gadget {
1327 FixableGadget(Kind K) : Gadget(K) {}
1329 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1330 bool isWarningGadget() const final {
return false; }
1335 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1336 return std::nullopt;
1345 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1346 getStrategyImplications()
const {
1347 return std::nullopt;
1351static bool isSupportedVariable(
const DeclRefExpr &Node) {
1363 dyn_cast<ClassTemplateSpecializationDecl>(
RecordDecl);
1364 if (!class_template_specialization_decl)
1369 if (template_args.
size() == 0)
1380class UniquePtrArrayAccessGadget :
public WarningGadget {
1382 static constexpr const char *
const AccessorTag =
"unique_ptr_array_access";
1383 const CXXOperatorCallExpr *AccessorExpr;
1387 : WarningGadget(
Kind::UniquePtrArrayAccess),
1388 AccessorExpr(
Result.getNodeAs<CXXOperatorCallExpr>(AccessorTag)) {
1389 assert(AccessorExpr &&
1390 "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr");
1393 static bool classof(
const Gadget *G) {
1394 return G->getKind() == Kind::UniquePtrArrayAccess;
1397 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1400 const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(S);
1401 if (!OpCall || OpCall->
getOperator() != OO_Subscript)
1408 const CXXMethodDecl *
Method =
1413 if (
Method->getOverloadedOperator() != OO_Subscript)
1417 if (!isUniquePtrArray(RecordDecl))
1420 const Expr *IndexExpr = OpCall->
getArg(1);
1421 clang::Expr::EvalResult Eval;
1427 Result.addNode(AccessorTag, DynTypedNode::create(*OpCall));
1430 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1431 bool IsRelatedToDecl,
1432 ASTContext &Ctx)
const override {
1434 DynTypedNode::create(*AccessorExpr), IsRelatedToDecl, Ctx);
1437 SourceLocation getSourceLoc()
const override {
1439 return AccessorExpr->getOperatorLoc();
1440 return SourceLocation();
1443 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1444 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1447using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1448using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1452class IncrementGadget :
public WarningGadget {
1453 static constexpr const char *
const OpTag =
"op";
1454 const UnaryOperator *Op;
1458 : WarningGadget(
Kind::Increment),
1459 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1461 static bool classof(
const Gadget *G) {
1462 return G->getKind() == Kind::Increment;
1465 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1467 const auto *UO = dyn_cast<UnaryOperator>(S);
1472 Result.addNode(OpTag, DynTypedNode::create(*UO));
1476 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1477 bool IsRelatedToDecl,
1478 ASTContext &Ctx)
const override {
1481 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1483 DeclUseList getClaimedVarUseSites()
const override {
1484 SmallVector<const DeclRefExpr *, 2> Uses;
1485 if (
const auto *DRE =
1486 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1487 Uses.push_back(DRE);
1490 return std::move(Uses);
1493 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1494 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1500class DecrementGadget :
public WarningGadget {
1501 static constexpr const char *
const OpTag =
"op";
1502 const UnaryOperator *Op;
1506 : WarningGadget(
Kind::Decrement),
1507 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1509 static bool classof(
const Gadget *G) {
1510 return G->getKind() == Kind::Decrement;
1513 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1515 const auto *UO = dyn_cast<UnaryOperator>(S);
1520 Result.addNode(OpTag, DynTypedNode::create(*UO));
1524 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1525 bool IsRelatedToDecl,
1526 ASTContext &Ctx)
const override {
1529 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1531 DeclUseList getClaimedVarUseSites()
const override {
1532 if (
const auto *DRE =
1533 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1540 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1541 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1547class ArraySubscriptGadget :
public WarningGadget {
1548 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1549 const ArraySubscriptExpr *ASE;
1554 ASE(
Result.getNodeAs<ArraySubscriptExpr>(ArraySubscrTag)) {}
1556 static bool classof(
const Gadget *G) {
1557 return G->getKind() == Kind::ArraySubscript;
1560 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1562 const auto *ASE = dyn_cast<ArraySubscriptExpr>(S);
1565 const auto *
const Base = ASE->getBase()->IgnoreParenImpCasts();
1568 const auto *Idx = dyn_cast<IntegerLiteral>(ASE->getIdx());
1569 bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
1573 Result.addNode(ArraySubscrTag, DynTypedNode::create(*ASE));
1577 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1578 bool IsRelatedToDecl,
1579 ASTContext &Ctx)
const override {
1582 SourceLocation getSourceLoc()
const override {
return ASE->getBeginLoc(); }
1584 DeclUseList getClaimedVarUseSites()
const override {
1585 if (
const auto *DRE =
1586 dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
1593 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1594 return {ASE->getBase()->IgnoreParenImpCasts()};
1602class PointerArithmeticGadget :
public WarningGadget {
1603 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1604 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1605 const BinaryOperator *PA;
1610 : WarningGadget(
Kind::PointerArithmetic),
1611 PA(
Result.getNodeAs<BinaryOperator>(PointerArithmeticTag)),
1612 Ptr(
Result.getNodeAs<Expr>(PointerArithmeticPointerTag)) {}
1614 static bool classof(
const Gadget *G) {
1615 return G->getKind() == Kind::PointerArithmetic;
1618 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1620 const auto *BO = dyn_cast<BinaryOperator>(S);
1623 const auto *LHS = BO->
getLHS();
1624 const auto *RHS = BO->
getRHS();
1629 RHS->getType()->isEnumeralType())) {
1630 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*LHS));
1631 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1637 (LHS->getType()->isIntegerType() || LHS->getType()->isEnumeralType())) {
1638 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*RHS));
1639 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1645 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1646 bool IsRelatedToDecl,
1647 ASTContext &Ctx)
const override {
1650 SourceLocation getSourceLoc()
const override {
return PA->getBeginLoc(); }
1652 DeclUseList getClaimedVarUseSites()
const override {
1653 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts())) {
1660 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1661 return {Ptr->IgnoreParenImpCasts()};
1668class SpanTwoParamConstructorGadget :
public WarningGadget {
1669 static constexpr const char *
const SpanTwoParamConstructorTag =
1670 "spanTwoParamConstructor";
1671 const CXXConstructExpr *Ctor;
1675 : WarningGadget(
Kind::SpanTwoParamConstructor),
1676 Ctor(
Result.getNodeAs<CXXConstructExpr>(SpanTwoParamConstructorTag)) {}
1678 static bool classof(
const Gadget *G) {
1679 return G->getKind() == Kind::SpanTwoParamConstructor;
1683 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1686 const auto *CDecl = CE->getConstructor();
1687 const auto *CRecordDecl = CDecl->getParent();
1688 auto HasTwoParamSpanCtorDecl =
1689 CRecordDecl->isInStdNamespace() &&
1690 CDecl->getDeclName().getAsString() ==
"span" && CE->getNumArgs() == 2;
1693 Result.addNode(SpanTwoParamConstructorTag, DynTypedNode::create(*CE));
1697 static bool matches(
const Stmt *S, ASTContext &Ctx,
1698 const UnsafeBufferUsageHandler *Handler,
1705 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1706 bool IsRelatedToDecl,
1707 ASTContext &Ctx)
const override {
1710 SourceLocation getSourceLoc()
const override {
return Ctor->getBeginLoc(); }
1712 DeclUseList getClaimedVarUseSites()
const override {
1715 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->getArg(0))) {
1722 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1729class PointerInitGadget :
public FixableGadget {
1731 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1732 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1733 const VarDecl *PtrInitLHS;
1734 const DeclRefExpr *PtrInitRHS;
1738 : FixableGadget(
Kind::PointerInit),
1739 PtrInitLHS(
Result.getNodeAs<VarDecl>(PointerInitLHSTag)),
1740 PtrInitRHS(
Result.getNodeAs<DeclRefExpr>(PointerInitRHSTag)) {}
1742 static bool classof(
const Gadget *G) {
1743 return G->getKind() == Kind::PointerInit;
1746 static bool matches(
const Stmt *S,
1747 llvm::SmallVectorImpl<MatchResult> &Results) {
1748 const DeclStmt *DS = dyn_cast<DeclStmt>(S);
1757 const auto *DRE = dyn_cast<DeclRefExpr>(
Init->IgnoreImpCasts());
1758 if (!DRE || !
hasPointerType(*DRE) || !isSupportedVariable(*DRE)) {
1762 R.addNode(PointerInitLHSTag, DynTypedNode::create(*VD));
1763 R.addNode(PointerInitRHSTag, DynTypedNode::create(*DRE));
1764 Results.emplace_back(std::move(R));
1768 virtual std::optional<FixItList>
1769 getFixits(
const FixitStrategy &S)
const override;
1770 SourceLocation getSourceLoc()
const override {
1771 return PtrInitRHS->getBeginLoc();
1774 virtual DeclUseList getClaimedVarUseSites()
const override {
1775 return DeclUseList{PtrInitRHS};
1778 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1779 getStrategyImplications()
const override {
1780 return std::make_pair(PtrInitLHS,
cast<VarDecl>(PtrInitRHS->getDecl()));
1789class PtrToPtrAssignmentGadget :
public FixableGadget {
1791 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1792 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1793 const DeclRefExpr *PtrLHS;
1794 const DeclRefExpr *PtrRHS;
1798 : FixableGadget(
Kind::PtrToPtrAssignment),
1799 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1800 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1802 static bool classof(
const Gadget *G) {
1803 return G->getKind() == Kind::PtrToPtrAssignment;
1806 static bool matches(
const Stmt *S,
1807 llvm::SmallVectorImpl<MatchResult> &Results) {
1808 size_t SizeBefore = Results.size();
1810 const auto *BO = dyn_cast<BinaryOperator>(S);
1811 if (!BO || BO->
getOpcode() != BO_Assign)
1814 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1816 !isSupportedVariable(*RHSRef)) {
1819 const auto *LHS = BO->
getLHS();
1820 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1822 !isSupportedVariable(*LHSRef)) {
1826 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1827 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1828 Results.emplace_back(std::move(R));
1830 return SizeBefore != Results.size();
1833 virtual std::optional<FixItList>
1834 getFixits(
const FixitStrategy &S)
const override;
1835 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1837 virtual DeclUseList getClaimedVarUseSites()
const override {
1838 return DeclUseList{PtrLHS, PtrRHS};
1841 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1842 getStrategyImplications()
const override {
1853class CArrayToPtrAssignmentGadget :
public FixableGadget {
1855 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1856 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1857 const DeclRefExpr *PtrLHS;
1858 const DeclRefExpr *PtrRHS;
1862 : FixableGadget(
Kind::CArrayToPtrAssignment),
1863 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1864 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1866 static bool classof(
const Gadget *G) {
1867 return G->getKind() == Kind::CArrayToPtrAssignment;
1870 static bool matches(
const Stmt *S,
1871 llvm::SmallVectorImpl<MatchResult> &Results) {
1872 size_t SizeBefore = Results.size();
1874 const auto *BO = dyn_cast<BinaryOperator>(S);
1875 if (!BO || BO->
getOpcode() != BO_Assign)
1878 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1881 !isSupportedVariable(*RHSRef)) {
1884 const auto *LHS = BO->
getLHS();
1885 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1887 !isSupportedVariable(*LHSRef)) {
1891 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1892 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1893 Results.emplace_back(std::move(R));
1895 return SizeBefore != Results.size();
1898 virtual std::optional<FixItList>
1899 getFixits(
const FixitStrategy &S)
const override;
1900 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1902 virtual DeclUseList getClaimedVarUseSites()
const override {
1903 return DeclUseList{PtrLHS, PtrRHS};
1906 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1907 getStrategyImplications()
const override {
1914class UnsafeBufferUsageAttrGadget :
public WarningGadget {
1915 constexpr static const char *
const OpTag =
"attr_expr";
1920 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
1921 Op(
Result.getNodeAs<Expr>(OpTag)) {}
1923 static bool classof(
const Gadget *G) {
1924 return G->getKind() == Kind::UnsafeBufferUsageAttr;
1927 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1929 if (
auto *CE = dyn_cast<CallExpr>(S)) {
1930 if (CE->getDirectCallee() &&
1931 CE->getDirectCallee()->hasAttr<UnsafeBufferUsageAttr>()) {
1932 Result.addNode(OpTag, DynTypedNode::create(*CE));
1936 if (
auto *ME = dyn_cast<MemberExpr>(S)) {
1939 if (ME->getMemberDecl()->hasAttr<UnsafeBufferUsageAttr>()) {
1940 Result.addNode(OpTag, DynTypedNode::create(*ME));
1947 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1948 bool IsRelatedToDecl,
1949 ASTContext &Ctx)
const override {
1952 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1954 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1956 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1962class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
1963 constexpr static const char *
const OpTag =
"cxx_construct_expr";
1964 const CXXConstructExpr *Op;
1968 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
1969 Op(
Result.getNodeAs<CXXConstructExpr>(OpTag)) {}
1971 static bool classof(
const Gadget *G) {
1972 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
1976 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1977 if (!CE || !CE->getConstructor()->hasAttr<UnsafeBufferUsageAttr>())
1981 if (SpanTwoParamConstructorGadget::matches(CE, Ctx, Tmp))
1983 Result.addNode(OpTag, DynTypedNode::create(*CE));
1987 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1988 bool IsRelatedToDecl,
1989 ASTContext &Ctx)
const override {
1992 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1994 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1996 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2003class DataInvocationGadget :
public WarningGadget {
2004 constexpr static const char *
const OpTag =
"data_invocation_expr";
2005 const ExplicitCastExpr *Op;
2009 : WarningGadget(
Kind::DataInvocation),
2010 Op(
Result.getNodeAs<ExplicitCastExpr>(OpTag)) {}
2012 static bool classof(
const Gadget *G) {
2013 return G->getKind() == Kind::DataInvocation;
2016 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2018 auto *CE = dyn_cast<ExplicitCastExpr>(S);
2021 for (
auto *Child : CE->children()) {
2022 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Child);
2023 MCE && isDataFunction(MCE)) {
2024 Result.addNode(OpTag, DynTypedNode::create(*CE));
2027 if (
auto *
Paren = dyn_cast<ParenExpr>(Child)) {
2028 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(
Paren->getSubExpr());
2029 MCE && isDataFunction(MCE)) {
2030 Result.addNode(OpTag, DynTypedNode::create(*CE));
2038 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2039 bool IsRelatedToDecl,
2040 ASTContext &Ctx)
const override {
2043 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2045 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2048 static bool isDataFunction(
const CXXMemberCallExpr *call) {
2055 if (method->getNameAsString() ==
"data" &&
2056 method->getParent()->isInStdNamespace() &&
2057 llvm::is_contained({SIZED_CONTAINER_OR_VIEW_LIST},
2058 method->getParent()->getName()))
2063 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2066class UnsafeLibcFunctionCallGadget :
public WarningGadget {
2067 const CallExpr *
const Call;
2068 const Expr *UnsafeArg =
nullptr;
2069 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
2071 constexpr static const char *
const UnsafeSprintfTag =
2072 "UnsafeLibcFunctionCall_sprintf";
2073 constexpr static const char *
const UnsafeSizedByTag =
2074 "UnsafeLibcFunctionCall_sized_by";
2075 constexpr static const char *
const UnsafeStringTag =
2076 "UnsafeLibcFunctionCall_string";
2077 constexpr static const char *
const UnsafeVaListTag =
2078 "UnsafeLibcFunctionCall_va_list";
2091 } WarnedFunKind = OTHERS;
2094 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2095 Call(
Result.getNodeAs<CallExpr>(Tag)) {
2096 if (
Result.getNodeAs<Decl>(UnsafeSprintfTag))
2097 WarnedFunKind = SPRINTF;
2098 else if (
auto *E =
Result.getNodeAs<Expr>(UnsafeStringTag)) {
2099 WarnedFunKind = STRING;
2101 }
else if (
Result.getNodeAs<CallExpr>(UnsafeSizedByTag)) {
2102 WarnedFunKind = SIZED_BY;
2103 UnsafeArg = Call->getArg(0);
2104 }
else if (
Result.getNodeAs<Decl>(UnsafeVaListTag))
2105 WarnedFunKind = VA_LIST;
2108 static bool matches(
const Stmt *S, ASTContext &Ctx,
2109 const UnsafeBufferUsageHandler *Handler,
2113 auto *CE = dyn_cast<CallExpr>(S);
2114 if (!CE || !CE->getDirectCallee())
2116 const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
2120 bool IsGlobalAndNotInAnyNamespace =
2121 FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
2125 if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
2131 auto isSingleStringLiteralArg =
false;
2132 if (CE->getNumArgs() == 1) {
2133 isSingleStringLiteralArg =
2136 if (!isSingleStringLiteralArg) {
2139 Result.addNode(Tag, DynTypedNode::create(*CE));
2143 Result.addNode(Tag, DynTypedNode::create(*CE));
2144 Result.addNode(UnsafeVaListTag, DynTypedNode::create(*FD));
2148 Result.addNode(Tag, DynTypedNode::create(*CE));
2149 Result.addNode(UnsafeSprintfTag, DynTypedNode::create(*FD));
2155 Result.addNode(Tag, DynTypedNode::create(*CE));
2156 Result.addNode(UnsafeSizedByTag, DynTypedNode::create(*CE));
2161 Result.addNode(Tag, DynTypedNode::create(*CE));
2168 const Stmt *getBaseStmt()
const {
return Call; }
2170 SourceLocation getSourceLoc()
const override {
return Call->getBeginLoc(); }
2172 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2173 bool IsRelatedToDecl,
2174 ASTContext &Ctx)
const override {
2178 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2180 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2183class UnsafeFormatAttributedFunctionCallGadget :
public WarningGadget {
2184 const CallExpr *
const Call;
2185 const Expr *UnsafeArg =
nullptr;
2186 constexpr static const char *
const Tag =
"UnsafeFormatAttributedFunctionCall";
2187 constexpr static const char *
const UnsafeStringTag =
2188 "UnsafeFormatAttributedFunctionCall_string";
2192 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2193 Call(
Result.getNodeAs<CallExpr>(Tag)),
2194 UnsafeArg(
Result.getNodeAs<Expr>(UnsafeStringTag)) {}
2196 static bool matches(
const Stmt *S, ASTContext &Ctx,
2197 const UnsafeBufferUsageHandler *Handler,
2201 auto *CE = dyn_cast<CallExpr>(S);
2202 if (!CE || !CE->getDirectCallee())
2204 const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
2208 const FormatAttr *Attr =
nullptr;
2209 bool IsPrintf =
false;
2210 bool AnyAttr = llvm::any_of(
2211 FD->specific_attrs<FormatAttr>(),
2212 [&Attr, &IsPrintf](
const FormatAttr *FA) ->
bool {
2213 if (const auto *II = FA->getType()) {
2214 if (II->getName() ==
"printf" || II->getName() ==
"scanf") {
2216 IsPrintf = II->getName() ==
"printf";
2222 const Expr *UnsafeArg;
2224 if (AnyAttr && !IsPrintf &&
2225 (CE->getNumArgs() >=
static_cast<unsigned>(Attr->getFirstArg()))) {
2227 Result.addNode(Tag, DynTypedNode::create(*CE));
2233 Attr->getFormatIdx() - 1,
2234 Attr->getFirstArg() - 1)) {
2235 Result.addNode(Tag, DynTypedNode::create(*CE));
2236 Result.addNode(UnsafeStringTag, DynTypedNode::create(*UnsafeArg));
2242 const Stmt *getBaseStmt()
const {
return Call; }
2247 bool IsRelatedToDecl,
2251 Call, UnsafeLibcFunctionCallGadget::UnsafeKind::STRING, Ctx,
2255 Call, UnsafeLibcFunctionCallGadget::UnsafeKind::OTHERS, Ctx);
2258 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2266class ULCArraySubscriptGadget :
public FixableGadget {
2268 static constexpr const char *
const ULCArraySubscriptTag =
2269 "ArraySubscriptUnderULC";
2270 const ArraySubscriptExpr *Node;
2274 : FixableGadget(
Kind::ULCArraySubscript),
2275 Node(
Result.getNodeAs<ArraySubscriptExpr>(ULCArraySubscriptTag)) {
2276 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2279 static bool classof(
const Gadget *G) {
2280 return G->getKind() == Kind::ULCArraySubscript;
2283 static bool matches(
const Stmt *S,
2284 llvm::SmallVectorImpl<MatchResult> &Results) {
2285 size_t SizeBefore = Results.size();
2287 const auto *ASE = dyn_cast<ArraySubscriptExpr>(E);
2293 !isSupportedVariable(*DRE))
2296 R.addNode(ULCArraySubscriptTag, DynTypedNode::create(*ASE));
2297 Results.emplace_back(std::move(R));
2299 return SizeBefore != Results.size();
2302 virtual std::optional<FixItList>
2303 getFixits(
const FixitStrategy &S)
const override;
2304 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2306 virtual DeclUseList getClaimedVarUseSites()
const override {
2307 if (
const auto *DRE =
2308 dyn_cast<DeclRefExpr>(Node->getBase()->IgnoreImpCasts())) {
2318class UPCStandalonePointerGadget :
public FixableGadget {
2320 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
2321 const DeclRefExpr *Node;
2325 : FixableGadget(
Kind::UPCStandalonePointer),
2326 Node(
Result.getNodeAs<DeclRefExpr>(DeclRefExprTag)) {
2327 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2330 static bool classof(
const Gadget *G) {
2331 return G->getKind() == Kind::UPCStandalonePointer;
2334 static bool matches(
const Stmt *S,
2335 llvm::SmallVectorImpl<MatchResult> &Results) {
2336 size_t SizeBefore = Results.size();
2338 auto *E = dyn_cast<Expr>(S);
2343 !isSupportedVariable(*DRE))
2346 R.addNode(DeclRefExprTag, DynTypedNode::create(*DRE));
2347 Results.emplace_back(std::move(R));
2349 return SizeBefore != Results.size();
2352 virtual std::optional<FixItList>
2353 getFixits(
const FixitStrategy &S)
const override;
2354 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2356 virtual DeclUseList getClaimedVarUseSites()
const override {
return {Node}; }
2359class PointerDereferenceGadget :
public FixableGadget {
2360 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2361 static constexpr const char *
const OperatorTag =
"op";
2363 const DeclRefExpr *BaseDeclRefExpr =
nullptr;
2364 const UnaryOperator *Op =
nullptr;
2368 : FixableGadget(
Kind::PointerDereference),
2369 BaseDeclRefExpr(
Result.getNodeAs<DeclRefExpr>(BaseDeclRefExprTag)),
2370 Op(
Result.getNodeAs<UnaryOperator>(OperatorTag)) {}
2372 static bool classof(
const Gadget *G) {
2373 return G->getKind() == Kind::PointerDereference;
2376 static bool matches(
const Stmt *S,
2377 llvm::SmallVectorImpl<MatchResult> &Results) {
2378 size_t SizeBefore = Results.size();
2380 const auto *UO = dyn_cast<UnaryOperator>(S);
2383 const auto *CE = dyn_cast<Expr>(UO->
getSubExpr());
2386 CE = CE->IgnoreParenImpCasts();
2387 const auto *DRE = dyn_cast<DeclRefExpr>(CE);
2388 if (!DRE || !isSupportedVariable(*DRE))
2391 R.addNode(BaseDeclRefExprTag, DynTypedNode::create(*DRE));
2392 R.addNode(OperatorTag, DynTypedNode::create(*UO));
2393 Results.emplace_back(std::move(R));
2395 return SizeBefore != Results.size();
2398 DeclUseList getClaimedVarUseSites()
const override {
2399 return {BaseDeclRefExpr};
2402 virtual std::optional<FixItList>
2403 getFixits(
const FixitStrategy &S)
const override;
2404 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2410class UPCAddressofArraySubscriptGadget :
public FixableGadget {
2412 static constexpr const char *
const UPCAddressofArraySubscriptTag =
2413 "AddressofArraySubscriptUnderUPC";
2414 const UnaryOperator *Node;
2418 : FixableGadget(
Kind::ULCArraySubscript),
2419 Node(
Result.getNodeAs<UnaryOperator>(UPCAddressofArraySubscriptTag)) {
2420 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2423 static bool classof(
const Gadget *G) {
2424 return G->getKind() == Kind::UPCAddressofArraySubscript;
2427 static bool matches(
const Stmt *S,
2428 llvm::SmallVectorImpl<MatchResult> &Results) {
2429 size_t SizeBefore = Results.size();
2431 auto *E = dyn_cast<Expr>(S);
2435 if (!UO || UO->
getOpcode() != UO_AddrOf)
2437 const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->
getSubExpr());
2442 if (!DRE || !isSupportedVariable(*DRE))
2445 R.addNode(UPCAddressofArraySubscriptTag, DynTypedNode::create(*UO));
2446 Results.emplace_back(std::move(R));
2448 return SizeBefore != Results.size();
2451 virtual std::optional<FixItList>
2452 getFixits(
const FixitStrategy &)
const override;
2453 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2455 virtual DeclUseList getClaimedVarUseSites()
const override {
2468class DeclUseTracker {
2469 using UseSetTy = llvm::SmallPtrSet<const DeclRefExpr *, 16>;
2470 using DefMapTy = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
2473 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
2477 DeclUseTracker() =
default;
2478 DeclUseTracker(
const DeclUseTracker &) =
delete;
2479 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
2480 DeclUseTracker(DeclUseTracker &&) =
default;
2481 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
2484 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
2487 void claimUse(
const DeclRefExpr *DRE) {
2488 assert(Uses->count(DRE) &&
2489 "DRE not found or claimed by multiple matchers!");
2494 bool hasUnclaimedUses(
const VarDecl *VD)
const {
2496 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
2501 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
2503 for (
auto use : *Uses) {
2505 ReturnSet.insert(use);
2511 void discoverDecl(
const DeclStmt *DS) {
2512 for (
const Decl *D : DS->
decls()) {
2513 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
2524 const DeclStmt *lookupDecl(
const VarDecl *VD)
const {
2525 return Defs.lookup(VD);
2534 static constexpr const char *
const UPCPreIncrementTag =
2535 "PointerPreIncrementUnderUPC";
2540 : FixableGadget(Kind::UPCPreIncrement),
2542 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2546 return G->getKind() == Kind::UPCPreIncrement;
2555 size_t SizeBefore = Results.size();
2557 auto *E = dyn_cast<Expr>(S);
2561 if (!UO || UO->
getOpcode() != UO_PreInc)
2563 const auto *DRE = dyn_cast<DeclRefExpr>(UO->
getSubExpr());
2564 if (!DRE || !isSupportedVariable(*DRE))
2568 Results.emplace_back(std::move(R));
2570 return SizeBefore != Results.size();
2573 virtual std::optional<FixItList>
2578 return {dyn_cast<DeclRefExpr>(Node->getSubExpr())};
2586 static constexpr const char *
const UUCAddAssignTag =
2587 "PointerAddAssignUnderUUC";
2588 static constexpr const char *
const OffsetTag =
"Offset";
2591 const Expr *Offset =
nullptr;
2595 : FixableGadget(Kind::UUCAddAssign),
2598 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2602 return G->getKind() == Kind::UUCAddAssign;
2607 size_t SizeBefore = Results.size();
2609 const auto *E = dyn_cast<Expr>(S);
2613 if (!BO || BO->
getOpcode() != BO_AddAssign)
2615 const auto *DRE = dyn_cast<DeclRefExpr>(BO->
getLHS());
2621 Results.emplace_back(std::move(R));
2623 return SizeBefore != Results.size();
2626 virtual std::optional<FixItList>
2631 return {dyn_cast<DeclRefExpr>(Node->getLHS())};
2638 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2639 static constexpr const char *
const DerefOpTag =
"DerefOp";
2640 static constexpr const char *
const AddOpTag =
"AddOp";
2641 static constexpr const char *
const OffsetTag =
"Offset";
2650 : FixableGadget(Kind::DerefSimplePtrArithFixable),
2658 auto IsPtr = [](
const Expr *E, MatchResult &R) {
2662 if (!DRE || !isSupportedVariable(*DRE))
2667 const auto IsPlusOverPtrAndInteger = [&IsPtr](
const Expr *E,
2669 const auto *BO = dyn_cast<BinaryOperator>(E);
2673 const auto *LHS = BO->
getLHS();
2674 const auto *RHS = BO->
getRHS();
2687 size_t SizeBefore = Results.size();
2688 const auto InnerMatcher = [&IsPlusOverPtrAndInteger,
2689 &Results](
const Expr *E) {
2690 const auto *UO = dyn_cast<UnaryOperator>(E);
2696 if (IsPlusOverPtrAndInteger(Operand, R)) {
2698 Results.emplace_back(std::move(R));
2702 return SizeBefore != Results.size();
2705 virtual std::optional<FixItList>
2708 return DerefOp->getBeginLoc();
2712 return {BaseDeclRefExpr};
2720 : WarningGadgets(WarningGadgets) {}
2729#define WARNING_GADGET(name) \
2730 if (name##Gadget::matches(S, Ctx, Result) && \
2731 notInSafeBufferOptOut(*S, &Handler)) { \
2732 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2735#define WARNING_OPTIONAL_GADGET(name) \
2736 if (name##Gadget::matches(S, Ctx, &Handler, Result) && \
2737 notInSafeBufferOptOut(*S, &Handler)) { \
2738 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2741#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2746 WarningGadgetList &WarningGadgets;
2753 DeclUseTracker &Tracker)
2754 : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
2758 bool matchFound =
false;
2765#define FIXABLE_GADGET(name) \
2766 if (name##Gadget::matches(S, Results)) { \
2767 for (const auto &R : Results) { \
2768 FixableGadgets.push_back(std::make_unique<name##Gadget>(R)); \
2769 matchFound = true; \
2773#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2776 if (
auto *DRE = findDeclRefExpr(S); DRE) {
2777 Tracker.discoverUse(DRE);
2783 if (
auto *DS = findDeclStmt(S); DS) {
2784 Tracker.discoverDecl(DS);
2792 const auto *DRE = dyn_cast<DeclRefExpr>(S);
2800 const DeclStmt *findDeclStmt(
const Stmt *S) {
2801 const auto *DS = dyn_cast<DeclStmt>(S);
2806 FixableGadgetList &FixableGadgets;
2807 DeclUseTracker &Tracker;
2813 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2814 WarningGadgetList &WarningGadgets,
2815 DeclUseTracker &Tracker) {
2818 if (EmitSuggestions) {
2827 return N1->getBeginLoc().getRawEncoding() <
2828 N2->getBeginLoc().getRawEncoding();
2838 const Expr *UnsafeArg =
nullptr)
override {}
2846 bool IsRelatedToDecl,
2863 FixableGadgetList FixableGadgets;
2864 WarningGadgetList WarningGadgets;
2865 DeclUseTracker Tracker;
2866 MockReporter IgnoreHandler;
2869 FixableGadgets, WarningGadgets, Tracker);
2871 std::set<const Expr *>
Result;
2872 for (
auto &G : WarningGadgets) {
2873 for (
const Expr *E : G->getUnsafePtrs()) {
2882 std::map<const VarDecl *, std::set<const WarningGadget *>,
2896 for (
auto &G : AllUnsafeOperations) {
2897 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
2899 bool AssociatedWithVarDecl =
false;
2900 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
2901 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2902 result.
byVar[VD].insert(G.get());
2903 AssociatedWithVarDecl =
true;
2907 if (!AssociatedWithVarDecl) {
2908 result.
noVar.push_back(G.get());
2916 std::map<const VarDecl *, std::set<const FixableGadget *>,
2926 for (
auto &F : AllFixableOperations) {
2927 DeclUseList DREs = F->getClaimedVarUseSites();
2930 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2931 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
2935 return FixablesForUnsafeVars;
2942 std::vector<const FixItHint *>
All;
2946 std::sort(
All.begin(),
All.end(),
2948 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
2949 H2->RemoveRange.getBegin());
2957 Hint->RemoveRange.getBegin())) {
2969std::optional<FixItList>
2970PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2973 switch (S.
lookup(LeftVD)) {
2977 return std::nullopt;
2979 return std::nullopt;
2982 return std::nullopt;
2984 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2986 return std::nullopt;
2990static inline std::optional<FixItList>
createDataFixit(
const ASTContext &Ctx,
2991 const DeclRefExpr *DRE);
2993std::optional<FixItList>
2994CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
3013 if (S.
lookup(LeftVD) == FixitStrategy::Kind::Span) {
3014 if (S.
lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
3017 }
else if (S.
lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
3018 if (S.
lookup(RightVD) == FixitStrategy::Kind::Array) {
3022 return std::nullopt;
3025std::optional<FixItList>
3026PointerInitGadget::getFixits(
const FixitStrategy &S)
const {
3027 const auto *LeftVD = PtrInitLHS;
3029 switch (S.
lookup(LeftVD)) {
3030 case FixitStrategy::Kind::Span:
3031 if (S.
lookup(RightVD) == FixitStrategy::Kind::Span)
3033 return std::nullopt;
3034 case FixitStrategy::Kind::Wontfix:
3035 return std::nullopt;
3036 case FixitStrategy::Kind::Iterator:
3037 case FixitStrategy::Kind::Array:
3038 return std::nullopt;
3039 case FixitStrategy::Kind::Vector:
3040 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3042 return std::nullopt;
3048 if (ConstVal->isNegative())
3055std::optional<FixItList>
3056ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
3057 if (
const auto *DRE =
3059 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3061 case FixitStrategy::Kind::Span: {
3065 const ASTContext &Ctx =
3068 return std::nullopt;
3072 case FixitStrategy::Kind::Array:
3074 case FixitStrategy::Kind::Wontfix:
3075 case FixitStrategy::Kind::Iterator:
3076 case FixitStrategy::Kind::Vector:
3077 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3080 return std::nullopt;
3083static std::optional<FixItList>
3086std::optional<FixItList>
3087UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
3088 auto DREs = getClaimedVarUseSites();
3092 case FixitStrategy::Kind::Span:
3094 case FixitStrategy::Kind::Wontfix:
3095 case FixitStrategy::Kind::Iterator:
3096 case FixitStrategy::Kind::Array:
3097 return std::nullopt;
3098 case FixitStrategy::Kind::Vector:
3099 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3101 return std::nullopt;
3106 static const char *
const EOL =
"\n";
3113 std::string
s = std::string(
"<# ");
3114 s += HintTextToUser;
3120template <
typename NodeTy>
3121static std::optional<SourceLocation>
3124 if (
unsigned TkLen =
3131 return std::nullopt;
3144 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
3145 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
3146 VD->getBeginLoc())) &&
3147 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
3148 At->getRange().getBegin()));
3152 AttrRangeOverlapping;
3194 std::optional<Qualifiers> Quals = std::nullopt) {
3195 const char *
const SpanOpen =
"std::span<";
3198 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
3199 return SpanOpen + EltTyText.str() +
'>';
3202std::optional<FixItList>
3204 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->getDecl());
3209 if (
auto ConstVal = Offset->getIntegerConstantExpr(Ctx))
3210 if (ConstVal->isNegative())
3211 return std::nullopt;
3232 const Expr *LHS = AddOp->getLHS(), *RHS = AddOp->getRHS();
3239 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
3241 return std::nullopt;
3246 std::optional<SourceLocation> AddOpLocation =
3248 std::optional<SourceLocation> DerefOpLocation =
3251 if (!AddOpLocation || !DerefOpLocation)
3252 return std::nullopt;
3262 return std::nullopt;
3265std::optional<FixItList>
3266PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
3277 if (
auto LocPastOperand =
3284 case FixitStrategy::Kind::Iterator:
3285 case FixitStrategy::Kind::Array:
3286 return std::nullopt;
3287 case FixitStrategy::Kind::Vector:
3288 llvm_unreachable(
"FixitStrategy not implemented yet!");
3289 case FixitStrategy::Kind::Wontfix:
3290 llvm_unreachable(
"Invalid strategy!");
3293 return std::nullopt;
3300 std::optional<SourceLocation> EndOfOperand =
3306 return std::nullopt;
3311std::optional<FixItList>
3312UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
3315 case FixitStrategy::Kind::Array:
3316 case FixitStrategy::Kind::Span: {
3321 case FixitStrategy::Kind::Wontfix:
3322 case FixitStrategy::Kind::Iterator:
3323 return std::nullopt;
3324 case FixitStrategy::Kind::Vector:
3325 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3328 return std::nullopt;
3333static std::optional<FixItList>
3340 const Expr *Idx = ArraySub->getIdx();
3343 std::stringstream SS;
3344 bool IdxIsLitZero =
false;
3347 if ((*ICE).isZero())
3348 IdxIsLitZero =
true;
3349 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
3351 return std::nullopt;
3355 SS << (*DreString).str() <<
".data()";
3357 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
3359 return std::nullopt;
3361 SS <<
"&" << (*DreString).str() <<
".data()"
3362 <<
"[" << (*IndexString).str() <<
"]";
3368std::optional<FixItList>
3372 if (DREs.size() != 1)
3373 return std::nullopt;
3375 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3379 const Stmt *AddAssignNode = Node;
3380 StringRef varName = VD->
getName();
3384 return std::nullopt;
3388 (Offset->IgnoreParens()->getBeginLoc() == Offset->getBeginLoc());
3389 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
3393 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
3395 if (!AddAssignLocation)
3396 return std::nullopt;
3403 Offset->getEndLoc().getLocWithOffset(1),
")"));
3407 return std::nullopt;
3410std::optional<FixItList>
3414 if (DREs.size() != 1)
3415 return std::nullopt;
3417 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3420 std::stringstream SS;
3421 StringRef varName = VD->
getName();
3425 SS <<
"(" << varName.data() <<
" = " << varName.data()
3426 <<
".subspan(1)).data()";
3427 std::optional<SourceLocation> PreIncLocation =
3429 if (!PreIncLocation)
3430 return std::nullopt;
3433 SourceRange(Node->getBeginLoc(), *PreIncLocation), SS.str()));
3437 return std::nullopt;
3455static std::optional<FixItList>
3457 const StringRef UserFillPlaceHolder) {
3465 if (
Init->isNullPointerConstant(
3470 NPC_ValueDependentIsNotNull)) {
3471 std::optional<SourceLocation> InitLocation =
3474 return std::nullopt;
3482 std::string ExtentText = UserFillPlaceHolder.data();
3483 StringRef One =
"1";
3488 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
3493 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
3494 if (!Ext->HasSideEffects(Ctx)) {
3495 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
3497 return std::nullopt;
3498 ExtentText = *ExtentString;
3500 }
else if (!CxxNew->isArray())
3512 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
3513 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
3514 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
3521 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
3524 return std::nullopt;
3526 StrBuffer.append(
", ");
3527 StrBuffer.append(ExtentText);
3528 StrBuffer.append(
"}");
3534#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
3535 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
3536 "failed to produce fixit for declaration '" + \
3537 (D)->getNameAsString() + "'" + (Msg))
3539#define DEBUG_NOTE_DECL_FAIL(D, Msg)
3545static std::optional<std::string>
3549 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3554 return std::nullopt;
3556 std::string SpanTyText =
"std::span<";
3558 SpanTyText.append(*PteTyText);
3560 if (PteTyQualifiers) {
3561 SpanTyText.append(
" ");
3562 SpanTyText.append(PteTyQualifiers->getAsString());
3564 SpanTyText.append(
">");
3583 const StringRef UserFillPlaceHolder,
3597 std::stringstream SS;
3602 std::optional<FixItList> InitFixIts =
3606 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
3607 std::make_move_iterator(InitFixIts->end()));
3614 if (!EndLocForReplacement.
isValid()) {
3664static std::optional<FixItList>
3670 return std::nullopt;
3675 std::vector<std::string> NewTysTexts(NumParms);
3676 std::vector<bool> ParmsMask(NumParms,
false);
3677 bool AtLeastOneParmToFix =
false;
3679 for (
unsigned i = 0; i < NumParms; i++) {
3686 return std::nullopt;
3688 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3689 std::optional<std::string> PteTyText =
3694 return std::nullopt;
3698 ParmsMask[i] =
true;
3699 AtLeastOneParmToFix =
true;
3701 if (!AtLeastOneParmToFix)
3708 const auto NewOverloadSignatureCreator =
3709 [&
SM, &LangOpts, &NewTysTexts,
3710 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3711 std::stringstream SS;
3719 SS << Prefix->str();
3721 return std::nullopt;
3725 for (
unsigned i = 0; i < NumParms; i++) {
3733 SS << NewTysTexts[i];
3736 SS <<
' ' << II->getName().str();
3737 }
else if (
auto ParmTypeText =
3741 SS << ParmTypeText->str();
3743 return std::nullopt;
3744 if (i != NumParms - 1)
3753 const auto OldOverloadDefCreator =
3754 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3755 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3756 std::stringstream SS;
3764 << FDPrefix->str() <<
"{";
3766 return std::nullopt;
3769 SS <<
"return " << FunQualName->str() <<
"(";
3771 return std::nullopt;
3775 for (
unsigned i = 0; i < NumParms; i++) {
3784 return std::nullopt;
3791 if (i != NumParms - 1)
3802 std::optional<SourceLocation> Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3806 if (FReDecl->isThisDeclarationADefinition()) {
3807 assert(FReDecl == FD &&
"inconsistent function definition");
3810 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3816 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3819 FReDecl->getBeginLoc(),
" ")));
3822 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3844 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3860 std::stringstream SS;
3863 if (PteTyQualifiers)
3872 SS <<
' ' << PVDNameText->str();
3878 const DeclUseTracker &Tracker,
3881 const DeclStmt *DS = Tracker.lookupDecl(VD);
3884 " : variables declared this way not implemented yet");
3908 const QualType &ArrayEltT = CAT->getElementType();
3909 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
3918 auto MaybeElemTypeTxt =
3921 if (!MaybeElemTypeTxt)
3923 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
3928 while (NextTok && !NextTok->is(tok::l_square) &&
3941 if (!MaybeArraySizeTxt)
3943 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
3944 if (ArraySizeTxt.empty()) {
3955 std::optional<StringRef> IdentText =
3964 llvm::raw_svector_ostream OS(Replacement);
3965 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
3966 << IdentText->str();
3976 const DeclUseTracker &Tracker,
3979 const DeclStmt *DS = Tracker.lookupDecl(VD);
3980 assert(DS &&
"Fixing non-local variables not implemented yet!");
3999 const DeclUseTracker &Tracker,
ASTContext &Ctx,
4001 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
4002 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
4003 if (!FD || FD != D) {
4014 if (FD->isMain() || FD->isConstexpr() ||
4021 FD->isOverloadedOperator()) {
4030 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
4048 llvm_unreachable(
"FixitStrategy not implemented yet!");
4050 llvm_unreachable(
"Invalid strategy!");
4052 llvm_unreachable(
"Unknown strategy!");
4060 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
4062 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
4079 std::map<const VarDecl *, FixItList> &FixItsForVariable,
4084 for (
const auto &[VD, Ignore] : FixItsForVariable) {
4086 if (llvm::any_of(Grp,
4087 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
4088 return !FixItsForVariable.count(GrpMember);
4093 ToErase.push_back(
Member);
4096 for (
auto *VarToErase : ToErase)
4097 FixItsForVariable.erase(VarToErase);
4108 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
4112 FixItList FixItsSharedByParms{};
4114 std::optional<FixItList> OverloadFixes =
4117 if (OverloadFixes) {
4118 FixItsSharedByParms.append(*OverloadFixes);
4124 FixItsForVariable.erase(
Member);
4126 return FixItsSharedByParms;
4130static std::map<const VarDecl *, FixItList>
4139 std::map<const VarDecl *, FixItList> FixItsForVariable;
4144 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
4145 FixItsForVariable[VD] =
4149 if (FixItsForVariable[VD].empty()) {
4150 FixItsForVariable.erase(VD);
4153 for (
const auto &F : Fixables) {
4154 std::optional<FixItList> Fixits = F->getFixits(S);
4157 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
4158 Fixits->begin(), Fixits->end());
4163 VD, F->getSourceLoc(),
4164 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
4167 FixItsForVariable.erase(VD);
4186 FixItList FixItsSharedByParms{};
4188 if (
auto *FD = dyn_cast<FunctionDecl>(D))
4190 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
4194 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
4197 for (
auto &[Var, Ignore] : FixItsForVariable) {
4198 bool AnyParm =
false;
4199 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
4201 for (
const VarDecl *GrpMate : VarGroupForVD) {
4204 if (FixItsForVariable.count(GrpMate))
4205 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
4209 assert(!FixItsSharedByParms.empty() &&
4210 "Should not try to fix a parameter that does not belong to a "
4212 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
4219 for (
auto Iter = FinalFixItsForVariable.begin();
4220 Iter != FinalFixItsForVariable.end();)
4223 Iter = FinalFixItsForVariable.erase(Iter);
4226 return FinalFixItsForVariable;
4229template <
typename VarDeclIterTy>
4233 for (
const VarDecl *VD : UnsafeVars) {
4244 const std::vector<VarGrpTy> Groups;
4245 const std::map<const VarDecl *, unsigned> &VarGrpMap;
4246 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
4250 const std::vector<VarGrpTy> &Groups,
4251 const std::map<const VarDecl *, unsigned> &VarGrpMap,
4252 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
4253 : Groups(Groups), VarGrpMap(VarGrpMap),
4254 GrpsUnionForParms(GrpsUnionForParms) {}
4257 if (GrpsUnionForParms.contains(Var)) {
4260 return GrpsUnionForParms.getArrayRef();
4265 auto It = VarGrpMap.find(Var);
4267 if (It == VarGrpMap.end())
4269 return Groups[It->second];
4273 return GrpsUnionForParms.getArrayRef();
4278 WarningGadgetList WarningGadgets,
4279 DeclUseTracker Tracker,
4281 bool EmitSuggestions) {
4282 if (!EmitSuggestions) {
4286 for (
const auto &G : WarningGadgets) {
4287 G->handleUnsafeOperation(Handler,
false,
4293 assert(FixableGadgets.empty() &&
4294 "Fixable gadgets found but suggestions not requested!");
4300 if (!WarningGadgets.empty()) {
4304 for (
const auto &G : FixableGadgets) {
4305 for (
const auto *DRE : G->getClaimedVarUseSites()) {
4306 Tracker.claimUse(DRE);
4322 if (WarningGadgets.empty())
4330 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
4333 for (
auto it = FixablesForAllVars.
byVar.cbegin();
4334 it != FixablesForAllVars.
byVar.cend();) {
4339 (
"failed to produce fixit for '" +
4340 it->first->getNameAsString() +
4341 "' : neither local nor a parameter"));
4343 it = FixablesForAllVars.
byVar.erase(it);
4344 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
4347 (
"failed to produce fixit for '" +
4348 it->first->getNameAsString() +
4349 "' : has a reference type"));
4351 it = FixablesForAllVars.
byVar.erase(it);
4352 }
else if (Tracker.hasUnclaimedUses(it->first)) {
4353 it = FixablesForAllVars.
byVar.erase(it);
4354 }
else if (it->first->isInitCapture()) {
4357 (
"failed to produce fixit for '" +
4358 it->first->getNameAsString() +
4359 "' : init capture"));
4361 it = FixablesForAllVars.
byVar.erase(it);
4368 for (
const auto &it : UnsafeOps.
byVar) {
4369 const VarDecl *
const UnsafeVD = it.first;
4370 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
4371 if (UnclaimedDREs.empty())
4375 std::string UnclaimedUseTrace =
4380 (
"failed to produce fixit for '" + UnfixedVDName +
4381 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
4382 UnclaimedUseTrace));
4389 llvm::DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
4390 DepMapTy DependenciesMap{};
4391 DepMapTy PtrAssignmentGraph{};
4393 for (
const auto &it : FixablesForAllVars.
byVar) {
4394 for (
const FixableGadget *fixable : it.second) {
4395 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
4396 fixable->getStrategyImplications();
4398 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
4399 PtrAssignmentGraph[Impl.first].insert(Impl.second);
4421 std::set<const VarDecl *> VisitedVarsDirected{};
4422 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4423 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
4425 std::queue<const VarDecl *> QueueDirected{};
4426 QueueDirected.push(Var);
4427 while (!QueueDirected.empty()) {
4428 const VarDecl *CurrentVar = QueueDirected.front();
4429 QueueDirected.pop();
4430 VisitedVarsDirected.insert(CurrentVar);
4431 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
4432 for (
const VarDecl *Adj : AdjacentNodes) {
4433 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
4434 QueueDirected.push(Adj);
4436 DependenciesMap[Var].insert(Adj);
4437 DependenciesMap[Adj].insert(Var);
4444 std::vector<VarGrpTy> Groups;
4448 std::map<const VarDecl *, unsigned> VarGrpMap;
4450 llvm::SetVector<const VarDecl *>
4455 std::set<const VarDecl *> VisitedVars{};
4456 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4457 if (VisitedVars.find(Var) == VisitedVars.end()) {
4458 VarGrpTy &VarGroup = Groups.emplace_back();
4459 std::queue<const VarDecl *> Queue{};
4462 while (!Queue.empty()) {
4463 const VarDecl *CurrentVar = Queue.front();
4465 VisitedVars.insert(CurrentVar);
4466 VarGroup.push_back(CurrentVar);
4467 auto AdjacentNodes = DependenciesMap[CurrentVar];
4468 for (
const VarDecl *Adj : AdjacentNodes) {
4469 if (VisitedVars.find(Adj) == VisitedVars.end()) {
4475 bool HasParm =
false;
4476 unsigned GrpIdx = Groups.size() - 1;
4478 for (
const VarDecl *
V : VarGroup) {
4479 VarGrpMap[
V] = GrpIdx;
4484 GrpsUnionForParms.insert_range(VarGroup);
4506 for (
auto I = FixablesForAllVars.
byVar.begin();
4507 I != FixablesForAllVars.
byVar.end();) {
4509 if (!VisitedVars.count((*I).first)) {
4511 I = FixablesForAllVars.
byVar.erase(I);
4519 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
4521 return FixablesForAllVars.
byVar.count(
V);
4528 FixItsForVariableGroup =
4530 Tracker, Handler, VarGrpMgr);
4532 for (
const auto &G : UnsafeOps.
noVar) {
4533 G->handleUnsafeOperation(Handler,
false,
4537 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
4538 auto FixItsIt = FixItsForVariableGroup.find(VD);
4540 FixItsIt != FixItsForVariableGroup.end()
4541 ? std::move(FixItsIt->second)
4544 for (
const auto &G : WarningGadgets) {
4545 G->handleUnsafeOperation(Handler,
true,
4553 bool EmitSuggestions) {
4562 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
4566 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
4567 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
4572 if (FReDecl->isExternC()) {
4575 EmitSuggestions =
false;
4580 Stmts.push_back(FD->getBody());
4582 if (
const auto *ID = dyn_cast<CXXConstructorDecl>(D)) {
4584 Stmts.push_back(CI->getInit());
4588 Stmts.push_back(D->
getBody());
4591 assert(!Stmts.empty());
4593 FixableGadgetList FixableGadgets;
4594 WarningGadgetList WarningGadgets;
4595 DeclUseTracker Tracker;
4596 for (
Stmt *S : Stmts) {
4598 WarningGadgets, Tracker);
4600 applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
4601 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,...
unsigned getArgIndex() const
bool hasDataArgument() const
HowSpecified getHowSpecified() const
unsigned getConstantAmount() const
const OptionalAmount & getPrecision() const
const PrintfConversionSpecifier & getConversionSpecifier() const
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
void matchEachArgumentWithParamType(const CallExpr &Node, llvm::function_ref< void(QualType, const Expr *)> OnParamAndArg)
bool anyConflict(const llvm::SmallVectorImpl< FixItHint > &FixIts, const SourceManager &SM)
bool matches(const til::SExpr *E1, const til::SExpr *E2)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
SourceLocation getVarDeclIdentifierLoc(const DeclaratorDecl *VD)
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 isPredefinedUnsafeLibcFunc(const FunctionDecl &Node)
static bool hasUnsafeSnprintfBuffer(const CallExpr &Node, ASTContext &Ctx)
static bool isUnsafeVaListPrintfFunc(const FunctionDecl &Node)
static bool isUnsafeSprintfFunc(const FunctionDecl &Node)
static bool hasUnsafeFormatOrSArg(ASTContext &Ctx, const CallExpr *Call, const Expr *&UnsafeArg, const unsigned FmtIdx, std::optional< const unsigned > FmtArgIdx=std::nullopt, bool isKprintf=false)
static bool isNormalPrintfFunc(const FunctionDecl &Node)
bool operator()(const NodeTy *N1, const NodeTy *N2) const
std::map< const VarDecl *, std::set< const FixableGadget * >, CompareNode< VarDecl > > byVar
std::map< const VarDecl *, std::set< const WarningGadget * >, CompareNode< VarDecl > > byVar
llvm::SmallVector< const WarningGadget *, 16 > noVar
SourceLocation getBeginLoc() const
getBeginLoc - Retrieve the location of the first token.
SourceLocation getEndLoc() const LLVM_READONLY
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.
const BoundNodes Nodes
Contains the nodes bound on the current match.
StringRef matchLibcName(StringRef Name)
StringRef matchName(StringRef FunName, bool isBuiltin)
StringRef matchLibcNameOrBuiltinChk(StringRef Name)