22#include "llvm/ADT/APSInt.h"
23#include "llvm/ADT/SmallVector.h"
24#include "llvm/ADT/StringRef.h"
25#include "llvm/Support/Casting.h"
33using namespace ast_matchers;
40 std::string VisitStmt(
const Stmt *S) {
return S->getStmtClassName(); }
43 return "BinaryOperator(" + BO->
getOpcodeStr().str() +
")";
57static std::string getDREAncestorString(
const DeclRefExpr *DRE,
61 StmtDebugPrinter StmtPriner;
64 SS << StmtPriner.Visit(St);
68 if (StParents.
size() > 1)
69 return "unavailable due to multiple parents";
70 if (StParents.
size() == 0)
93 internal::ASTMatchFinder *Finder,
94 internal::BoundNodesTreeBuilder *Builder,
95 internal::ASTMatchFinder::BindKind Bind,
96 const bool ignoreUnevaluatedContext)
97 : Matcher(Matcher), Finder(Finder), Builder(Builder), Bind(Bind),
98 Matches(
false), ignoreUnevaluatedContext(ignoreUnevaluatedContext) {}
106 *Builder = ResultBindings;
125 if (isa<FunctionDecl, BlockDecl, ObjCMethodDecl>(
Node))
133 if (ignoreUnevaluatedContext)
135 return VisitorBase::TraverseGenericSelectionExpr(
Node);
140 if (ignoreUnevaluatedContext)
142 return VisitorBase::TraverseUnaryExprOrTypeTraitExpr(
Node);
147 if (ignoreUnevaluatedContext)
149 return VisitorBase::TraverseTypeOfExprTypeLoc(
Node);
154 if (ignoreUnevaluatedContext)
156 return VisitorBase::TraverseDecltypeTypeLoc(
Node);
161 if (ignoreUnevaluatedContext)
163 return VisitorBase::TraverseCXXNoexceptExpr(
Node);
168 if (ignoreUnevaluatedContext)
170 return VisitorBase::TraverseCXXTypeidExpr(
Node);
192 template <
typename T>
bool match(
const T &
Node) {
193 internal::BoundNodesTreeBuilder RecursiveBuilder(*Builder);
196 &RecursiveBuilder)) {
197 ResultBindings.addMatch(RecursiveBuilder);
199 if (Bind != internal::ASTMatchFinder::BK_All)
205 const internal::DynTypedMatcher *
const Matcher;
206 internal::ASTMatchFinder *
const Finder;
207 internal::BoundNodesTreeBuilder *
const Builder;
208 internal::BoundNodesTreeBuilder ResultBindings;
209 const internal::ASTMatchFinder::BindKind Bind;
211 bool ignoreUnevaluatedContext;
223 const DynTypedMatcher &DTM =
static_cast<DynTypedMatcher
>(innerMatcher);
232 const DynTypedMatcher &DTM =
static_cast<DynTypedMatcher
>(innerMatcher);
242 return !Handler->isSafeBufferOptOut(
Node.getBeginLoc());
247 return Handler->ignoreUnsafeBufferInContainer(
Node.getBeginLoc());
251 return innerMatcher.matches(*
Node.getSubExpr(), Finder, Builder);
256 return Node.getOpcode() == UnaryOperator::Opcode::UO_PreInc;
266 hasCastKind(CastKind::CK_LValueToRValue),
267 castSubExpr(innerMatcher)),
278static internal::Matcher<Stmt>
290 forEachArgumentWithParamType(
296 auto CastOperandMatcher =
298 hasCastKind(CastKind::CK_PointerToBoolean)),
301 auto CompOperandMatcher =
307 auto PtrSubtractionMatcher =
314 eachOf(hasLHS(InnerMatcher),
315 hasRHS(InnerMatcher)));
318 return stmt(
anyOf(CallArgMatcher, CastOperandMatcher, CompOperandMatcher,
319 PtrSubtractionMatcher));
334static internal::Matcher<Stmt>
341 auto IfStmtThen =
ifStmt(hasThen(InnerMatcher));
342 auto IfStmtElse =
ifStmt(hasElse(InnerMatcher));
344 return stmt(
anyOf(CompStmt, IfStmtThen, IfStmtElse));
356 assert(
Node.getNumArgs() == 2 &&
357 "expecting a two-parameter std::span constructor");
358 const Expr *Arg0 =
Node.getArg(0)->IgnoreImplicit();
359 const Expr *Arg1 =
Node.getArg(1)->IgnoreImplicit();
360 auto HaveEqualConstantValues = [&Finder](
const Expr *E0,
const Expr *E1) {
362 if (
auto E1CV = E1->getIntegerConstantExpr(Finder->getASTContext())) {
363 return APSInt::compareValues(*E0CV, *E1CV) == 0;
367 auto AreSameDRE = [](
const Expr *E0,
const Expr *E1) {
368 if (
auto *DRE0 = dyn_cast<DeclRefExpr>(E0))
369 if (
auto *DRE1 = dyn_cast<DeclRefExpr>(E1)) {
370 return DRE0->getDecl() == DRE1->getDecl();
374 std::optional<APSInt> Arg1CV =
377 if (Arg1CV && Arg1CV->isZero())
381 case Stmt::CXXNewExprClass:
382 if (
auto Size = cast<CXXNewExpr>(Arg0)->getArraySize()) {
384 return AreSameDRE((*Size)->IgnoreImplicit(), Arg1) ||
385 HaveEqualConstantValues(*Size, Arg1);
388 if (!cast<CXXNewExpr>(Arg0)->hasPlaceholderType()) {
390 return Arg1CV && Arg1CV->isOne();
393 case Stmt::UnaryOperatorClass:
394 if (cast<UnaryOperator>(Arg0)->getOpcode() ==
395 UnaryOperator::Opcode::UO_AddrOf)
397 return Arg1CV && Arg1CV->isOne();
406 const APSInt ConstArrSize =
407 APSInt(cast<ConstantArrayType>(Arg0Ty)->getSize());
410 return Arg1CV && APSInt::compareValues(ConstArrSize, *Arg1CV) == 0;
423 const auto *BaseDRE =
424 dyn_cast<DeclRefExpr>(
Node.getBase()->IgnoreParenImpCasts());
427 if (!BaseDRE->getDecl())
429 const auto *CATy = Finder->getASTContext().getAsConstantArrayType(
430 BaseDRE->getDecl()->getType());
434 if (
const auto *IdxLit = dyn_cast<IntegerLiteral>(
Node.getIdx())) {
435 const APInt ArrIdx = IdxLit->getValue();
438 if (ArrIdx.isNonNegative() &&
439 ArrIdx.getLimitedValue() < CATy->getLimitedSize())
470#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
476 using Matcher =
decltype(
stmt());
478 Gadget(Kind K) : K(K) {}
483 StringRef getDebugName()
const {
488#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
490 llvm_unreachable(
"Unhandled Gadget::Kind enum");
494 virtual bool isWarningGadget()
const = 0;
495 virtual const Stmt *getBaseStmt()
const = 0;
500 virtual DeclUseList getClaimedVarUseSites()
const = 0;
502 virtual ~Gadget() =
default;
510class WarningGadget :
public Gadget {
512 WarningGadget(Kind K) : Gadget(K) {}
514 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
515 bool isWarningGadget() const final {
return true; }
522class FixableGadget :
public Gadget {
524 FixableGadget(Kind K) : Gadget(K) {}
526 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
527 bool isWarningGadget() const final {
return false; }
532 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
542 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
543 getStrategyImplications()
const {
548static auto toSupportedVariable() {
return to(
varDecl()); }
550using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
551using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
555class IncrementGadget :
public WarningGadget {
556 static constexpr const char *
const OpTag =
"op";
561 : WarningGadget(
Kind::Increment),
564 static bool classof(
const Gadget *G) {
565 return G->getKind() == Kind::Increment;
568 static Matcher matcher() {
575 const UnaryOperator *getBaseStmt()
const override {
return Op; }
577 DeclUseList getClaimedVarUseSites()
const override {
579 if (
const auto *DRE =
584 return std::move(Uses);
590class DecrementGadget :
public WarningGadget {
591 static constexpr const char *
const OpTag =
"op";
596 : WarningGadget(
Kind::Decrement),
599 static bool classof(
const Gadget *G) {
600 return G->getKind() == Kind::Decrement;
603 static Matcher matcher() {
610 const UnaryOperator *getBaseStmt()
const override {
return Op; }
612 DeclUseList getClaimedVarUseSites()
const override {
613 if (
const auto *DRE =
624class ArraySubscriptGadget :
public WarningGadget {
625 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
630 : WarningGadget(
Kind::ArraySubscript),
633 static bool classof(
const Gadget *G) {
634 return G->getKind() == Kind::ArraySubscript;
637 static Matcher matcher() {
640 hasBase(ignoringParenImpCasts(
643 isSafeArraySubscript(),
647 ))).bind(ArraySubscrTag));
653 DeclUseList getClaimedVarUseSites()
const override {
654 if (
const auto *DRE =
667class PointerArithmeticGadget :
public WarningGadget {
668 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
669 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
675 : WarningGadget(
Kind::PointerArithmetic),
677 Ptr(Result.
Nodes.getNodeAs<
Expr>(PointerArithmeticPointerTag)) {}
679 static bool classof(
const Gadget *G) {
680 return G->getKind() == Kind::PointerArithmetic;
683 static Matcher matcher() {
684 auto HasIntegerType =
anyOf(hasType(isInteger()), hasType(
enumType()));
686 allOf(hasOperatorName(
"+"),
688 hasLHS(HasIntegerType));
690 allOf(
anyOf(hasOperatorName(
"+"), hasOperatorName(
"-"),
691 hasOperatorName(
"+="), hasOperatorName(
"-=")),
693 hasRHS(HasIntegerType));
696 .bind(PointerArithmeticTag));
699 const Stmt *getBaseStmt()
const override {
return PA; }
701 DeclUseList getClaimedVarUseSites()
const override {
712class SpanTwoParamConstructorGadget :
public WarningGadget {
713 static constexpr const char *
const SpanTwoParamConstructorTag =
714 "spanTwoParamConstructor";
719 : WarningGadget(
Kind::SpanTwoParamConstructor),
721 SpanTwoParamConstructorTag)) {}
723 static bool classof(
const Gadget *G) {
724 return G->getKind() == Kind::SpanTwoParamConstructor;
727 static Matcher matcher() {
730 parameterCountIs(2)));
733 unless(isSafeSpanTwoParamConstruct()))
734 .bind(SpanTwoParamConstructorTag));
737 const Stmt *getBaseStmt()
const override {
return Ctor; }
739 DeclUseList getClaimedVarUseSites()
const override {
742 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->
getArg(0))) {
743 if (isa<VarDecl>(DRE->
getDecl()))
754class PointerInitGadget :
public FixableGadget {
756 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
757 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
763 : FixableGadget(
Kind::PointerInit),
764 PtrInitLHS(Result.
Nodes.getNodeAs<
VarDecl>(PointerInitLHSTag)),
767 static bool classof(
const Gadget *G) {
768 return G->getKind() == Kind::PointerInit;
771 static Matcher matcher() {
772 auto PtrInitStmt =
declStmt(hasSingleDecl(
773 varDecl(hasInitializer(ignoringImpCasts(
775 .bind(PointerInitRHSTag))))
776 .bind(PointerInitLHSTag)));
778 return stmt(PtrInitStmt);
781 virtual std::optional<FixItList>
784 virtual const Stmt *getBaseStmt()
const override {
790 virtual DeclUseList getClaimedVarUseSites()
const override {
791 return DeclUseList{PtrInitRHS};
794 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
795 getStrategyImplications()
const override {
796 return std::make_pair(PtrInitLHS, cast<VarDecl>(PtrInitRHS->
getDecl()));
805class PtrToPtrAssignmentGadget :
public FixableGadget {
807 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
808 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
814 : FixableGadget(
Kind::PtrToPtrAssignment),
818 static bool classof(
const Gadget *G) {
819 return G->getKind() == Kind::PtrToPtrAssignment;
822 static Matcher matcher() {
824 allOf(hasOperatorName(
"="),
825 hasRHS(ignoringParenImpCasts(
827 .bind(PointerAssignRHSTag))),
829 .bind(PointerAssignLHSTag))));
834 virtual std::optional<FixItList>
837 virtual const Stmt *getBaseStmt()
const override {
843 virtual DeclUseList getClaimedVarUseSites()
const override {
844 return DeclUseList{PtrLHS, PtrRHS};
847 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
848 getStrategyImplications()
const override {
849 return std::make_pair(cast<VarDecl>(PtrLHS->
getDecl()),
850 cast<VarDecl>(PtrRHS->
getDecl()));
859class CArrayToPtrAssignmentGadget :
public FixableGadget {
861 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
862 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
868 : FixableGadget(
Kind::CArrayToPtrAssignment),
872 static bool classof(
const Gadget *G) {
873 return G->getKind() == Kind::CArrayToPtrAssignment;
876 static Matcher matcher() {
878 allOf(hasOperatorName(
"="),
879 hasRHS(ignoringParenImpCasts(
881 toSupportedVariable())
882 .bind(PointerAssignRHSTag))),
884 .bind(PointerAssignLHSTag))));
889 virtual std::optional<FixItList>
892 virtual const Stmt *getBaseStmt()
const override {
898 virtual DeclUseList getClaimedVarUseSites()
const override {
899 return DeclUseList{PtrLHS, PtrRHS};
902 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
903 getStrategyImplications()
const override {
910class UnsafeBufferUsageAttrGadget :
public WarningGadget {
911 constexpr static const char *
const OpTag =
"call_expr";
916 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
919 static bool classof(
const Gadget *G) {
920 return G->getKind() == Kind::UnsafeBufferUsageAttr;
923 static Matcher matcher() {
927 const Stmt *getBaseStmt()
const override {
return Op; }
929 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
936class DataInvocationGadget :
public WarningGadget {
937 constexpr static const char *
const OpTag =
"data_invocation_expr";
942 : WarningGadget(
Kind::DataInvocation),
945 static bool classof(
const Gadget *G) {
946 return G->getKind() == Kind::DataInvocation;
949 static Matcher matcher() {
956 const Stmt *getBaseStmt()
const override {
return Op; }
958 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
964class ULCArraySubscriptGadget :
public FixableGadget {
966 static constexpr const char *
const ULCArraySubscriptTag =
967 "ArraySubscriptUnderULC";
972 : FixableGadget(
Kind::ULCArraySubscript),
974 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
977 static bool classof(
const Gadget *G) {
978 return G->getKind() == Kind::ULCArraySubscript;
981 static Matcher matcher() {
983 auto BaseIsArrayOrPtrDRE = hasBase(
984 ignoringParenImpCasts(
declRefExpr(ArrayOrPtr, toSupportedVariable())));
991 virtual std::optional<FixItList>
994 virtual const Stmt *getBaseStmt()
const override {
return Node; }
996 virtual DeclUseList getClaimedVarUseSites()
const override {
997 if (
const auto *DRE =
998 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts())) {
1008class UPCStandalonePointerGadget :
public FixableGadget {
1010 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
1015 : FixableGadget(
Kind::UPCStandalonePointer),
1017 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
1020 static bool classof(
const Gadget *G) {
1021 return G->getKind() == Kind::UPCStandalonePointer;
1024 static Matcher matcher() {
1026 auto target =
expr(ignoringParenImpCasts(
1028 .bind(DeclRefExprTag)));
1032 virtual std::optional<FixItList>
1035 virtual const Stmt *getBaseStmt()
const override {
return Node; }
1037 virtual DeclUseList getClaimedVarUseSites()
const override {
return {
Node}; }
1040class PointerDereferenceGadget :
public FixableGadget {
1041 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
1042 static constexpr const char *
const OperatorTag =
"op";
1049 : FixableGadget(
Kind::PointerDereference),
1054 static bool classof(
const Gadget *G) {
1055 return G->getKind() == Kind::PointerDereference;
1058 static Matcher matcher() {
1061 hasOperatorName(
"*"),
1062 has(
expr(ignoringParenImpCasts(
1063 declRefExpr(toSupportedVariable()).bind(BaseDeclRefExprTag)))))
1069 DeclUseList getClaimedVarUseSites()
const override {
1070 return {BaseDeclRefExpr};
1073 virtual const Stmt *getBaseStmt() const final {
return Op; }
1075 virtual std::optional<FixItList>
1082class UPCAddressofArraySubscriptGadget :
public FixableGadget {
1084 static constexpr const char *
const UPCAddressofArraySubscriptTag =
1085 "AddressofArraySubscriptUnderUPC";
1090 : FixableGadget(
Kind::ULCArraySubscript),
1092 UPCAddressofArraySubscriptTag)) {
1093 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
1096 static bool classof(
const Gadget *G) {
1097 return G->getKind() == Kind::UPCAddressofArraySubscript;
1100 static Matcher matcher() {
1103 hasOperatorName(
"&"),
1105 ignoringParenImpCasts(
declRefExpr(toSupportedVariable()))))))
1106 .bind(UPCAddressofArraySubscriptTag)))));
1109 virtual std::optional<FixItList>
1112 virtual const Stmt *getBaseStmt()
const override {
return Node; }
1114 virtual DeclUseList getClaimedVarUseSites()
const override {
1115 const auto *ArraySubst = cast<ArraySubscriptExpr>(
Node->getSubExpr());
1117 cast<DeclRefExpr>(ArraySubst->getBase()->IgnoreParenImpCasts());
1127class DeclUseTracker {
1128 using UseSetTy = SmallSet<const DeclRefExpr *, 16>;
1129 using DefMapTy = DenseMap<const VarDecl *, const DeclStmt *>;
1132 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
1136 DeclUseTracker() =
default;
1137 DeclUseTracker(
const DeclUseTracker &) =
delete;
1138 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
1139 DeclUseTracker(DeclUseTracker &&) =
default;
1140 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
1143 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
1147 assert(Uses->count(DRE) &&
1148 "DRE not found or claimed by multiple matchers!");
1153 bool hasUnclaimedUses(
const VarDecl *VD)
const {
1155 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
1160 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
1162 for (
auto use : *Uses) {
1164 ReturnSet.insert(use);
1170 void discoverDecl(
const DeclStmt *DS) {
1172 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
1184 return Defs.lookup(VD);
1193 static constexpr const char *
const UPCPreIncrementTag =
1194 "PointerPreIncrementUnderUPC";
1199 : FixableGadget(Kind::UPCPreIncrement),
1201 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
1205 return G->getKind() == Kind::UPCPreIncrement;
1215 hasUnaryOperand(
declRefExpr(toSupportedVariable())))
1216 .bind(UPCPreIncrementTag)))));
1219 virtual std::optional<FixItList>
1225 return {dyn_cast<DeclRefExpr>(
Node->getSubExpr())};
1233 static constexpr const char *
const UUCAddAssignTag =
1234 "PointerAddAssignUnderUUC";
1235 static constexpr const char *
const OffsetTag =
"Offset";
1238 const Expr *Offset =
nullptr;
1242 : FixableGadget(Kind::UUCAddAssign),
1244 Offset(Result.
Nodes.getNodeAs<
Expr>(OffsetTag)) {
1245 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
1249 return G->getKind() == Kind::UUCAddAssign;
1259 toSupportedVariable())),
1260 hasRHS(
expr().bind(OffsetTag)))
1261 .bind(UUCAddAssignTag)))));
1265 virtual std::optional<FixItList>
1271 return {dyn_cast<DeclRefExpr>(
Node->getLHS())};
1278 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
1279 static constexpr const char *
const DerefOpTag =
"DerefOp";
1280 static constexpr const char *
const AddOpTag =
"AddOp";
1281 static constexpr const char *
const OffsetTag =
"Offset";
1290 : FixableGadget(Kind::DerefSimplePtrArithFixable),
1300 ignoringImpCasts(
declRefExpr(toSupportedVariable()).
1301 bind(BaseDeclRefExprTag)));
1302 auto PlusOverPtrAndInteger =
expr(
anyOf(
1310 hasOperatorName(
"*"),
1311 hasUnaryOperand(ignoringParens(PlusOverPtrAndInteger)))
1316 virtual std::optional<FixItList>
1323 return {BaseDeclRefExpr};
1328static std::tuple<FixableGadgetList, WarningGadgetList, DeclUseTracker>
1330 bool EmitSuggestions) {
1333 FixableGadgetList FixableGadgets;
1334 WarningGadgetList WarningGadgets;
1335 DeclUseTracker Tracker;
1343 [[maybe_unused]]
int numFound = 0;
1344#define NEXT ++numFound
1347 if (
const auto *DRE = Result.Nodes.getNodeAs<
DeclRefExpr>(
"any_dre")) {
1348 Tracker.discoverUse(DRE);
1352 if (
const auto *DS = Result.Nodes.getNodeAs<
DeclStmt>(
"any_ds")) {
1353 Tracker.discoverDecl(DS);
1360#define FIXABLE_GADGET(name) \
1361 if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
1362 FixableGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
1365#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1366#define WARNING_GADGET(name) \
1367 if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
1368 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
1371#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1373 assert(numFound >= 1 &&
"Gadgets not found in match result!");
1374 assert(numFound <= 1 &&
"Conflicting bind tags in gadgets!");
1379 GadgetFinderCallback CB;
1384 forEachDescendantEvaluatedStmt(
stmt(
anyOf(
1387 allOf(x ## Gadget::matcher().bind(#x), \
1388 notInSafeBufferOptOut(&Handler)),
1390 allOf(x ## Gadget::matcher().bind(#x), \
1391 notInSafeBufferOptOut(&Handler), \
1392 unless(ignoreUnsafeBufferInContainer(&Handler))),
1393#include
"clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1402 if (EmitSuggestions) {
1408 x ## Gadget::matcher().bind(#x),
1409#include
"clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1426 return {std::move(CB.FixableGadgets), std::move(CB.WarningGadgets),
1427 std::move(CB.Tracker)};
1433 return N1->getBeginLoc().getRawEncoding() <
1434 N2->getBeginLoc().getRawEncoding();
1439 std::map<const VarDecl *, std::set<const WarningGadget *>,
1453 for (
auto &G : AllUnsafeOperations) {
1454 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
1456 bool AssociatedWithVarDecl =
false;
1457 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
1458 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1459 result.
byVar[VD].insert(G.get());
1460 AssociatedWithVarDecl =
true;
1464 if (!AssociatedWithVarDecl) {
1465 result.
noVar.push_back(G.get());
1473 std::map<const VarDecl *, std::set<const FixableGadget *>,
1483 for (
auto &F : AllFixableOperations) {
1484 DeclUseList DREs = F->getClaimedVarUseSites();
1487 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1488 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
1492 return FixablesForUnsafeVars;
1499 std::vector<const FixItHint *> All;
1503 std::sort(All.begin(), All.end(),
1505 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
1506 H2->RemoveRange.getBegin());
1514 Hint->RemoveRange.getBegin())) {
1526std::optional<FixItList>
1527PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
1528 const auto *LeftVD = cast<VarDecl>(PtrLHS->
getDecl());
1529 const auto *RightVD = cast<VarDecl>(PtrRHS->
getDecl());
1530 switch (S.lookup(LeftVD)) {
1531 case FixitStrategy::Kind::Span:
1532 if (S.lookup(RightVD) == FixitStrategy::Kind::Span)
1534 return std::nullopt;
1535 case FixitStrategy::Kind::Wontfix:
1536 return std::nullopt;
1537 case FixitStrategy::Kind::Iterator:
1538 case FixitStrategy::Kind::Array:
1539 return std::nullopt;
1540 case FixitStrategy::Kind::Vector:
1541 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1543 return std::nullopt;
1550std::optional<FixItList>
1551CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
1552 const auto *LeftVD = cast<VarDecl>(PtrLHS->
getDecl());
1553 const auto *RightVD = cast<VarDecl>(PtrRHS->
getDecl());
1570 if (S.lookup(LeftVD) == FixitStrategy::Kind::Span) {
1571 if (S.lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
1574 }
else if (S.lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
1575 if (S.lookup(RightVD) == FixitStrategy::Kind::Array) {
1579 return std::nullopt;
1582std::optional<FixItList>
1584 const auto *LeftVD = PtrInitLHS;
1585 const auto *RightVD = cast<VarDecl>(PtrInitRHS->
getDecl());
1586 switch (S.lookup(LeftVD)) {
1587 case FixitStrategy::Kind::Span:
1588 if (S.lookup(RightVD) == FixitStrategy::Kind::Span)
1590 return std::nullopt;
1591 case FixitStrategy::Kind::Wontfix:
1592 return std::nullopt;
1593 case FixitStrategy::Kind::Iterator:
1594 case FixitStrategy::Kind::Array:
1595 return std::nullopt;
1596 case FixitStrategy::Kind::Vector:
1597 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1599 return std::nullopt;
1605 if (ConstVal->isNegative())
1612std::optional<FixItList>
1613ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
1614 if (
const auto *DRE =
1615 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts()))
1616 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1617 switch (S.lookup(VD)) {
1618 case FixitStrategy::Kind::Span: {
1625 return std::nullopt;
1629 case FixitStrategy::Kind::Array:
1631 case FixitStrategy::Kind::Wontfix:
1632 case FixitStrategy::Kind::Iterator:
1633 case FixitStrategy::Kind::Vector:
1634 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1637 return std::nullopt;
1640static std::optional<FixItList>
1643std::optional<FixItList>
1644UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
1645 auto DREs = getClaimedVarUseSites();
1646 const auto *VD = cast<VarDecl>(DREs.front()->getDecl());
1648 switch (S.lookup(VD)) {
1649 case FixitStrategy::Kind::Span:
1651 case FixitStrategy::Kind::Wontfix:
1652 case FixitStrategy::Kind::Iterator:
1653 case FixitStrategy::Kind::Array:
1654 return std::nullopt;
1655 case FixitStrategy::Kind::Vector:
1656 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1658 return std::nullopt;
1663 static const char *
const EOL =
"\n";
1669 std::string
s = std::string(
"<# ");
1670 s += HintTextToUser;
1676template <
typename NodeTy>
1677static std::optional<SourceLocation>
1686 return std::nullopt;
1690template <
typename NodeTy>
1698 return std::nullopt;
1705 std::optional<SourceLocation> LastCharLoc =
getPastLoc(E,
SM, LangOpts);
1712 return std::nullopt;
1725 return std::nullopt;
1737static std::optional<StringRef>
1746 return std::nullopt;
1747 return getRangeText({ParmIdentBeginLoc, ParmIdentEndLoc},
SM, LangOpts);
1760 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
1761 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
1762 VD->getBeginLoc())) &&
1763 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
1764 At->getRange().getBegin()));
1768 AttrRangeOverlapping;
1792static std::optional<std::string>
1795 std::optional<Qualifiers> *QualifiersToAppend) {
1800 "Expecting a VarDecl of type of pointer to object type");
1809 case TypeLoc::ConstantArray:
1810 case TypeLoc::IncompleteArray:
1811 case TypeLoc::VariableArray:
1812 case TypeLoc::DependentSizedArray:
1813 case TypeLoc::Decayed:
1814 assert(isa<ParmVarDecl>(VD) &&
"An array type shall not be treated as a "
1815 "pointer type unless it decays.");
1818 case TypeLoc::Pointer:
1822 return std::nullopt;
1827 return std::nullopt;
1835 return std::nullopt;
1842 if (!PteEndOfTokenLoc.
isValid())
1845 return std::nullopt;
1846 if (!
SM.isBeforeInTranslationUnit(PteEndOfTokenLoc, IdentLoc)) {
1853 return std::nullopt;
1888 std::optional<Qualifiers> Quals = std::nullopt) {
1889 const char *
const SpanOpen =
"std::span<";
1892 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
1893 return SpanOpen + EltTyText.str() +
'>';
1896std::optional<FixItList>
1898 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->
getDecl());
1900 if (VD &&
s.lookup(VD) == FixitStrategy::Kind::Span) {
1904 if (ConstVal->isNegative())
1905 return std::nullopt;
1933 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
1935 return std::nullopt;
1940 std::optional<SourceLocation> AddOpLocation =
1942 std::optional<SourceLocation> DerefOpLocation =
1945 if (!AddOpLocation || !DerefOpLocation)
1946 return std::nullopt;
1956 return std::nullopt;
1959std::optional<FixItList>
1960PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
1962 switch (S.lookup(VD)) {
1963 case FixitStrategy::Kind::Span: {
1971 if (
auto LocPastOperand =
1978 case FixitStrategy::Kind::Iterator:
1979 case FixitStrategy::Kind::Array:
1980 return std::nullopt;
1981 case FixitStrategy::Kind::Vector:
1982 llvm_unreachable(
"FixitStrategy not implemented yet!");
1983 case FixitStrategy::Kind::Wontfix:
1984 llvm_unreachable(
"Invalid strategy!");
1987 return std::nullopt;
1994 std::optional<SourceLocation> EndOfOperand =
2000 return std::nullopt;
2005std::optional<FixItList>
2006UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
2007 const auto VD = cast<VarDecl>(
Node->getDecl());
2008 switch (S.lookup(VD)) {
2009 case FixitStrategy::Kind::Array:
2010 case FixitStrategy::Kind::Span: {
2015 case FixitStrategy::Kind::Wontfix:
2016 case FixitStrategy::Kind::Iterator:
2017 return std::nullopt;
2018 case FixitStrategy::Kind::Vector:
2019 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2022 return std::nullopt;
2027static std::optional<FixItList>
2029 const auto *ArraySub = cast<ArraySubscriptExpr>(
Node->getSubExpr());
2030 const auto *DRE = cast<DeclRefExpr>(ArraySub->getBase()->IgnoreImpCasts());
2034 const Expr *Idx = ArraySub->getIdx();
2037 std::stringstream SS;
2038 bool IdxIsLitZero =
false;
2041 if ((*ICE).isZero())
2042 IdxIsLitZero =
true;
2043 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
2045 return std::nullopt;
2049 SS << (*DreString).str() <<
".data()";
2051 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
2053 return std::nullopt;
2055 SS <<
"&" << (*DreString).str() <<
".data()"
2056 <<
"[" << (*IndexString).str() <<
"]";
2062std::optional<FixItList>
2066 if (DREs.size() != 1)
2067 return std::nullopt;
2069 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
2070 if (S.lookup(VD) == FixitStrategy::Kind::Span) {
2074 StringRef varName = VD->
getName();
2078 return std::nullopt;
2083 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
2087 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
2089 if (!AddAssignLocation)
2090 return std::nullopt;
2101 return std::nullopt;
2104std::optional<FixItList>
2108 if (DREs.size() != 1)
2109 return std::nullopt;
2111 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
2112 if (S.lookup(VD) == FixitStrategy::Kind::Span) {
2114 std::stringstream SS;
2116 StringRef varName = VD->
getName();
2120 SS <<
"(" << varName.data() <<
" = " << varName.data()
2121 <<
".subspan(1)).data()";
2122 std::optional<SourceLocation> PreIncLocation =
2124 if (!PreIncLocation)
2125 return std::nullopt;
2132 return std::nullopt;
2150static std::optional<FixItList>
2152 const StringRef UserFillPlaceHolder) {
2160 if (
Init->isNullPointerConstant(
2165 NPC_ValueDependentIsNotNull)) {
2166 std::optional<SourceLocation> InitLocation =
2169 return std::nullopt;
2177 std::string ExtentText = UserFillPlaceHolder.data();
2178 StringRef One =
"1";
2183 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
2188 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
2189 if (!Ext->HasSideEffects(Ctx)) {
2190 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
2192 return std::nullopt;
2193 ExtentText = *ExtentString;
2195 }
else if (!CxxNew->isArray())
2207 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
2208 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
2209 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
2216 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
2219 return std::nullopt;
2221 StrBuffer.append(
", ");
2222 StrBuffer.append(ExtentText);
2223 StrBuffer.append(
"}");
2229#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
2230 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
2231 "failed to produce fixit for declaration '" + \
2232 (D)->getNameAsString() + "'" + (Msg))
2234#define DEBUG_NOTE_DECL_FAIL(D, Msg)
2240static std::optional<std::string>
2244 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
2249 return std::nullopt;
2251 std::string SpanTyText =
"std::span<";
2253 SpanTyText.append(*PteTyText);
2255 if (PteTyQualifiers) {
2256 SpanTyText.append(
" ");
2257 SpanTyText.append(PteTyQualifiers->getAsString());
2259 SpanTyText.append(
">");
2278 const StringRef UserFillPlaceHolder,
2292 std::stringstream SS;
2297 std::optional<FixItList> InitFixIts =
2301 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
2302 std::make_move_iterator(InitFixIts->end()));
2309 if (!EndLocForReplacement.
isValid()) {
2359static std::optional<FixItList>
2365 return std::nullopt;
2370 std::vector<std::string> NewTysTexts(NumParms);
2371 std::vector<bool> ParmsMask(NumParms,
false);
2372 bool AtLeastOneParmToFix =
false;
2374 for (
unsigned i = 0; i < NumParms; i++) {
2377 if (S.lookup(PVD) == FixitStrategy::Kind::Wontfix)
2379 if (S.lookup(PVD) != FixitStrategy::Kind::Span)
2381 return std::nullopt;
2383 std::optional<Qualifiers> PteTyQuals = std::nullopt;
2384 std::optional<std::string> PteTyText =
2389 return std::nullopt;
2393 ParmsMask[i] =
true;
2394 AtLeastOneParmToFix =
true;
2396 if (!AtLeastOneParmToFix)
2403 const auto NewOverloadSignatureCreator =
2404 [&
SM, &LangOpts, &NewTysTexts,
2405 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
2406 std::stringstream SS;
2414 SS << Prefix->str();
2416 return std::nullopt;
2420 for (
unsigned i = 0; i < NumParms; i++) {
2428 SS << NewTysTexts[i];
2431 SS <<
' ' << II->
getName().str();
2432 }
else if (
auto ParmTypeText =
2436 SS << ParmTypeText->str();
2438 return std::nullopt;
2439 if (i != NumParms - 1)
2448 const auto OldOverloadDefCreator =
2449 [&Handler, &
SM, &LangOpts, &NewTysTexts,
2450 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
2451 std::stringstream SS;
2459 << FDPrefix->str() <<
"{";
2461 return std::nullopt;
2464 SS <<
"return " << FunQualName->str() <<
"(";
2466 return std::nullopt;
2470 for (
unsigned i = 0; i < NumParms; i++) {
2479 return std::nullopt;
2486 if (i != NumParms - 1)
2497 std::optional<SourceLocation> Loc =
getPastLoc(FReDecl,
SM, LangOpts);
2501 if (FReDecl->isThisDeclarationADefinition()) {
2502 assert(FReDecl == FD &&
"inconsistent function definition");
2505 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
2511 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
2514 FReDecl->getBeginLoc(),
" ")));
2517 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
2539 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
2555 std::stringstream SS;
2558 if (PteTyQualifiers)
2567 SS <<
' ' << PVDNameText->str();
2573 const DeclUseTracker &Tracker,
2576 const DeclStmt *DS = Tracker.lookupDecl(VD);
2579 " : variables declared this way not implemented yet");
2602 if (
auto CAT = dyn_cast<clang::ConstantArrayType>(D->
getType())) {
2603 const QualType &ArrayEltT = CAT->getElementType();
2604 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
2613 auto MaybeElemTypeTxt =
2616 if (!MaybeElemTypeTxt)
2618 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
2623 while (NextTok && !NextTok->is(tok::l_square) &&
2636 if (!MaybeArraySizeTxt)
2638 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
2639 if (ArraySizeTxt.empty()) {
2650 std::optional<StringRef> IdentText =
2659 raw_svector_ostream OS(Replacement);
2660 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
2661 << IdentText->str();
2671 const DeclUseTracker &Tracker,
2674 const DeclStmt *DS = Tracker.lookupDecl(VD);
2675 assert(DS &&
"Fixing non-local variables not implemented yet!");
2694 const DeclUseTracker &Tracker,
ASTContext &Ctx,
2696 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
2697 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
2698 if (!FD || FD != D) {
2709 if (FD->isMain() || FD->isConstexpr() ||
2710 FD->getTemplatedKind() != FunctionDecl::TemplatedKind::TK_NonTemplate ||
2713 isa<CXXMethodDecl>(FD) ||
2715 (FD->hasBody() && isa<CXXTryStmt>(FD->getBody())) ||
2716 FD->isOverloadedOperator()) {
2723 case FixitStrategy::Kind::Span: {
2725 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
2734 case FixitStrategy::Kind::Array: {
2742 case FixitStrategy::Kind::Iterator:
2743 case FixitStrategy::Kind::Vector:
2744 llvm_unreachable(
"FixitStrategy not implemented yet!");
2745 case FixitStrategy::Kind::Wontfix:
2746 llvm_unreachable(
"Invalid strategy!");
2748 llvm_unreachable(
"Unknown strategy!");
2756 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
2758 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
2767 return isa<ParmVarDecl>(VD) &&
2775 std::map<const VarDecl *, FixItList> &FixItsForVariable,
2780 for (
const auto &[VD, Ignore] : FixItsForVariable) {
2782 if (llvm::any_of(Grp,
2783 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
2784 return !FixItsForVariable.count(GrpMember);
2789 ToErase.push_back(
Member);
2792 for (
auto *VarToErase : ToErase)
2793 FixItsForVariable.erase(VarToErase);
2804 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
2808 FixItList FixItsSharedByParms{};
2810 std::optional<FixItList> OverloadFixes =
2813 if (OverloadFixes) {
2814 FixItsSharedByParms.append(*OverloadFixes);
2820 FixItsForVariable.erase(
Member);
2822 return FixItsSharedByParms;
2826static std::map<const VarDecl *, FixItList>
2835 std::map<const VarDecl *, FixItList> FixItsForVariable;
2840 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
2841 FixItsForVariable[VD] =
2842 fixVariable(VD, S.lookup(VD), D, Tracker, Ctx, Handler);
2845 if (FixItsForVariable[VD].empty()) {
2846 FixItsForVariable.erase(VD);
2849 for (
const auto &F : Fixables) {
2850 std::optional<FixItList> Fixits = F->getFixits(S);
2853 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
2854 Fixits->begin(), Fixits->end());
2860 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
2863 FixItsForVariable.erase(VD);
2882 FixItList FixItsSharedByParms{};
2884 if (
auto *FD = dyn_cast<FunctionDecl>(D))
2886 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
2890 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
2893 for (
auto &[Var, Ignore] : FixItsForVariable) {
2894 bool AnyParm =
false;
2895 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
2897 for (
const VarDecl *GrpMate : VarGroupForVD) {
2900 if (FixItsForVariable.count(GrpMate))
2901 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
2905 assert(!FixItsSharedByParms.empty() &&
2906 "Should not try to fix a parameter that does not belong to a "
2908 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
2915 for (
auto Iter = FinalFixItsForVariable.begin();
2916 Iter != FinalFixItsForVariable.end();)
2919 Iter = FinalFixItsForVariable.erase(
Iter);
2922 return FinalFixItsForVariable;
2925template <
typename VarDeclIterTy>
2929 for (
const VarDecl *VD : UnsafeVars) {
2931 S.set(VD, FixitStrategy::Kind::Array);
2933 S.set(VD, FixitStrategy::Kind::Span);
2940 const std::vector<VarGrpTy> Groups;
2941 const std::map<const VarDecl *, unsigned> &VarGrpMap;
2942 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
2946 const std::vector<VarGrpTy> &Groups,
2947 const std::map<const VarDecl *, unsigned> &VarGrpMap,
2948 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
2949 : Groups(Groups), VarGrpMap(VarGrpMap),
2950 GrpsUnionForParms(GrpsUnionForParms) {}
2953 if (GrpsUnionForParms.contains(Var)) {
2956 return GrpsUnionForParms.getArrayRef();
2961 auto It = VarGrpMap.find(Var);
2963 if (It == VarGrpMap.end())
2964 return std::nullopt;
2965 return Groups[It->second];
2969 return GrpsUnionForParms.getArrayRef();
2975 bool EmitSuggestions) {
2984 if (
const auto *fd = dyn_cast<CXXMethodDecl>(D)) {
2985 if (fd->getParent()->isLambda() && fd->getParent()->isLocalClass())
2991 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
2993 if (FReDecl->isExternC()) {
2994 EmitSuggestions =
false;
3003 auto [FixableGadgets, WarningGadgets, Tracker] =
3006 if (!EmitSuggestions) {
3010 for (
const auto &G : WarningGadgets) {
3017 assert(FixableGadgets.size() == 0 &&
3018 "Fixable gadgets found but suggestions not requested!");
3024 if (!WarningGadgets.empty()) {
3028 for (
const auto &G : FixableGadgets) {
3029 for (
const auto *DRE : G->getClaimedVarUseSites()) {
3030 Tracker.claimUse(DRE);
3046 if (WarningGadgets.empty())
3052 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
3055 for (
auto it = FixablesForAllVars.
byVar.cbegin();
3056 it != FixablesForAllVars.
byVar.cend();) {
3058 if ((!it->first->isLocalVarDecl() && !isa<ParmVarDecl>(it->first))) {
3061 (
"failed to produce fixit for '" +
3062 it->first->getNameAsString() +
3063 "' : neither local nor a parameter"));
3065 it = FixablesForAllVars.
byVar.erase(it);
3066 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
3069 (
"failed to produce fixit for '" +
3070 it->first->getNameAsString() +
3071 "' : has a reference type"));
3073 it = FixablesForAllVars.
byVar.erase(it);
3074 }
else if (Tracker.hasUnclaimedUses(it->first)) {
3075 it = FixablesForAllVars.
byVar.erase(it);
3076 }
else if (it->first->isInitCapture()) {
3079 (
"failed to produce fixit for '" +
3080 it->first->getNameAsString() +
3081 "' : init capture"));
3083 it = FixablesForAllVars.
byVar.erase(it);
3090 for (
const auto &it : UnsafeOps.
byVar) {
3091 const VarDecl *
const UnsafeVD = it.first;
3092 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
3093 if (UnclaimedDREs.empty())
3097 std::string UnclaimedUseTrace =
3102 (
"failed to produce fixit for '" + UnfixedVDName +
3103 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
3104 UnclaimedUseTrace));
3110 using DepMapTy = DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
3111 DepMapTy DependenciesMap{};
3112 DepMapTy PtrAssignmentGraph{};
3114 for (
auto it : FixablesForAllVars.
byVar) {
3115 for (
const FixableGadget *fixable : it.second) {
3116 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
3117 fixable->getStrategyImplications();
3119 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
3120 PtrAssignmentGraph[Impl.first].insert(Impl.second);
3142 std::set<const VarDecl *> VisitedVarsDirected{};
3143 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
3144 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
3146 std::queue<const VarDecl *> QueueDirected{};
3147 QueueDirected.push(Var);
3148 while (!QueueDirected.empty()) {
3149 const VarDecl *CurrentVar = QueueDirected.front();
3150 QueueDirected.pop();
3151 VisitedVarsDirected.insert(CurrentVar);
3152 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
3153 for (
const VarDecl *Adj : AdjacentNodes) {
3154 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
3155 QueueDirected.push(Adj);
3157 DependenciesMap[Var].insert(Adj);
3158 DependenciesMap[Adj].insert(Var);
3165 std::vector<VarGrpTy> Groups;
3169 std::map<const VarDecl *, unsigned> VarGrpMap;
3171 llvm::SetVector<const VarDecl *>
3176 std::set<const VarDecl *> VisitedVars{};
3177 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
3178 if (VisitedVars.find(Var) == VisitedVars.end()) {
3179 VarGrpTy &VarGroup = Groups.emplace_back();
3180 std::queue<const VarDecl *> Queue{};
3183 while (!Queue.empty()) {
3184 const VarDecl *CurrentVar = Queue.front();
3186 VisitedVars.insert(CurrentVar);
3187 VarGroup.push_back(CurrentVar);
3188 auto AdjacentNodes = DependenciesMap[CurrentVar];
3189 for (
const VarDecl *Adj : AdjacentNodes) {
3190 if (VisitedVars.find(Adj) == VisitedVars.end()) {
3196 bool HasParm =
false;
3197 unsigned GrpIdx = Groups.size() - 1;
3199 for (
const VarDecl *
V : VarGroup) {
3200 VarGrpMap[
V] = GrpIdx;
3205 GrpsUnionForParms.insert(VarGroup.begin(), VarGroup.end());
3227 for (
auto I = FixablesForAllVars.
byVar.begin();
3228 I != FixablesForAllVars.
byVar.end();) {
3230 if (!VisitedVars.count((*I).first)) {
3232 I = FixablesForAllVars.
byVar.erase(I);
3240 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
3242 return FixablesForAllVars.
byVar.count(
V);
3246 if (isa<NamedDecl>(D))
3249 FixItsForVariableGroup =
3251 Tracker, Handler, VarGrpMgr);
3253 for (
const auto &G : UnsafeOps.
noVar) {
3258 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
3259 auto FixItsIt = FixItsForVariableGroup.find(VD);
3261 FixItsIt != FixItsForVariableGroup.end()
3262 ? std::move(FixItsIt->second)
3265 for (
const auto &G : WarningGadgets) {
Defines the clang::ASTContext interface.
BoundNodesTreeBuilder Nodes
#define AST_MATCHER(Type, DefineMatcher)
AST_MATCHER(Type, DefineMatcher) { ... } defines a zero parameter function named DefineMatcher() that...
#define AST_MATCHER_P(Type, DefineMatcher, ParamType, Param)
AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) { ... } defines a single-parameter function name...
static Decl::Kind getKind(const Decl *D)
static const Decl * getCanonicalDecl(const Decl *D)
llvm::MachO::Target Target
Defines the clang::Preprocessor interface.
static bool hasAttr(const Decl *D, bool IgnoreImplicitAttr)
Defines the clang::SourceLocation class and associated facilities.
static FixItList fixVariableWithSpan(const VarDecl *VD, const DeclUseTracker &Tracker, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static std::optional< FixItList > fixUPCAddressofArraySubscriptWithSpan(const UnaryOperator *Node)
static std::optional< StringRef > getExprText(const Expr *E, const SourceManager &SM, const LangOptions &LangOpts)
static WarningGadgetSets groupWarningGadgetsByVar(const WarningGadgetList &AllUnsafeOperations)
static StringRef getEndOfLine()
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 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)
#define FIXABLE_GADGET(name)
static FixItList fixVarDeclWithArray(const VarDecl *D, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
#define WARNING_GADGET(name)
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 std::optional< StringRef > getRangeText(SourceRange SR, const SourceManager &SM, const LangOptions &LangOpts)
static FixitStrategy getNaiveStrategy(llvm::iterator_range< VarDeclIterTy > UnsafeVars)
static std::optional< std::string > createSpanTypeForVarDecl(const VarDecl *VD, const ASTContext &Ctx)
static SourceLocation getVarDeclIdentifierLoc(const VarDecl *VD)
static std::optional< SourceLocation > getPastLoc(const NodeTy *Node, const SourceManager &SM, const LangOptions &LangOpts)
std::string getUserFillPlaceHolder(StringRef HintTextToUser="placeholder")
static bool hasConflictingOverload(const FunctionDecl *FD)
static std::optional< StringRef > getVarDeclIdentifierText(const VarDecl *VD, const SourceManager &SM, const LangOptions &LangOpts)
static std::optional< std::string > getPointeeTypeText(const VarDecl *VD, const SourceManager &SM, const LangOptions &LangOpts, std::optional< Qualifiers > *QualifiersToAppend)
static std::tuple< FixableGadgetList, WarningGadgetList, DeclUseTracker > findGadgets(const Decl *D, const UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
Scan the function and return a list of gadgets found with provided kits.
static bool isNonNegativeIntegerExpr(const Expr *Expr, const VarDecl *VD, const ASTContext &Ctx)
static bool overlapWithMacro(const FixItList &FixIts)
static bool hasUnsupportedSpecifiers(const VarDecl *VD, const SourceManager &SM)
#define DEBUG_NOTE_DECL_FAIL(D, Msg)
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 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)
static std::optional< StringRef > getFunNameText(const FunctionDecl *FD, const SourceManager &SM, const LangOptions &LangOpts)
#define WARNING_CONTAINER_GADGET(x)
__device__ __2f16 float __ockl_bool s
virtual std::optional< FixItList > getFixits(const FixitStrategy &s) const final
DerefSimplePtrArithFixableGadget(const MatchFinder::MatchResult &Result)
virtual const Stmt * getBaseStmt() const final
virtual DeclUseList getClaimedVarUseSites() const final
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
virtual const Stmt * getBaseStmt() const override
virtual DeclUseList getClaimedVarUseSites() const override
static bool classof(const Gadget *G)
UPCPreIncrementGadget(const MatchFinder::MatchResult &Result)
static bool classof(const Gadget *G)
UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
virtual const Stmt * getBaseStmt() const override
virtual DeclUseList getClaimedVarUseSites() 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,...
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.
const LangOptions & getLangOpts() 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.
Represents a C++11 noexcept expression (C++ [expr.unary.noexcept]).
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]).
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
static const char * getCastKindName(CastKind CK)
Represents a character-granular source range.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getEnd() const
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
bool isSingleResult() const
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.
Decl - This represents one declaration (or definition), e.g.
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...
SourceLocation getLocation() const
DeclContext * getDeclContext()
SourceLocation getBeginLoc() const LLVM_READONLY
NestedNameSpecifier * getQualifier() const
Retrieve the nested-name-specifier that qualifies the name of this declaration, if it was present in ...
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...
TypeSourceInfo * getTypeSourceInfo() const
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
const DynTypedNode * begin() const
A dynamically typed AST node container.
SourceRange getSourceRange() const
For nodes which represent textual entities in the source code, return their SourceRange.
const T * get() const
Retrieve the stored node as type T.
static DynTypedNode create(const T &Node)
Creates a DynTypedNode from Node.
ExplicitCastExpr - An explicit cast written in the source code.
This represents one expression.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Expr * IgnoreImplicit() LLVM_READONLY
Skip past any implicit AST nodes which might surround this expression until reaching a fixed point.
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
NullPointerConstantValueDependence
Enumeration used to describe how isNullPointerConstant() should cope with value-dependent expressions...
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc=nullptr) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
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.
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.
param_iterator param_begin()
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
DeclarationNameInfo getNameInfo() const
Represents a C11 generic selection.
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
static bool isAtEndOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroEnd=nullptr)
Returns true if the given MacroID location points at the last token of the macro expansion.
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 std::optional< Token > findNextToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Finds the token that comes right after the given location.
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.
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.
Wrapper for source info for pointers.
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
std::string getAsString() const
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue=nullptr)
Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
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.
SourceLocation getEndLoc() const LLVM_READONLY
StmtClass getStmtClass() const
SourceLocation getBeginLoc() const LLVM_READONLY
Base wrapper for a particular "section" of type source info.
UnqualTypeLoc getUnqualifiedLoc() const
Skips past any qualifiers, if this is qualified.
TypeLoc getNextTypeLoc() const
Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the TypeLoc is a PointerLoc and next Typ...
T castAs() const
Convert to the specified TypeLoc type, asserting that this TypeLoc is of the desired type.
SourceRange getSourceRange() const LLVM_READONLY
Get the full source range.
TypeLocClass getTypeLocClass() const
SourceLocation getEndLoc() const
Get the end source location.
SourceLocation getBeginLoc() const
Get the begin source location.
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
bool isConstantArrayType() const
bool isFunctionPointerType() const
bool isPointerType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
SourceLocation getOperatorLoc() const
getOperatorLoc - Return the location of the operator.
Expr * getSubExpr() const
SourceLocation getBeginLoc() const LLVM_READONLY
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...
void addDebugNoteForVar(const VarDecl *VD, SourceLocation Loc, std::string Text)
virtual std::string getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, StringRef WSSuffix="") 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.
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.
virtual VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm=nullptr) const =0
Returns the set of variables (including Var) that need to be fixed together in one step.
virtual VarGrpRef getGroupOfParms() const =0
Returns the non-empty group of variables that include parameters of the analyzing function,...
bool findMatch(const DynTypedNode &DynNode)
bool shouldVisitImplicitCode() const
bool TraverseDecl(Decl *Node)
bool TraverseCXXNoexceptExpr(CXXNoexceptExpr *Node)
RecursiveASTVisitor< MatchDescendantVisitor > VisitorBase
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc Node)
bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node)
MatchDescendantVisitor(const internal::DynTypedMatcher *Matcher, internal::ASTMatchFinder *Finder, internal::BoundNodesTreeBuilder *Builder, internal::ASTMatchFinder::BindKind Bind, const bool ignoreUnevaluatedContext)
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc Node)
bool shouldVisitTemplateInstantiations() const
bool TraverseCXXTypeidExpr(CXXTypeidExpr *Node)
bool TraverseStmt(Stmt *Node, DataRecursionQueue *Queue=nullptr)
bool TraverseGenericSelectionExpr(GenericSelectionExpr *Node)
Called when the Match registered for it was successfully found in the AST.
virtual void run(const MatchResult &Result)=0
Called on every match by the MatchFinder.
A class to allow finding matches over the Clang AST.
void addMatcher(const DeclarationMatcher &NodeMatch, MatchCallback *Action)
Adds a matcher to execute when running over the AST.
void match(const T &Node, ASTContext &Context)
Calls the registered callbacks on all matches on the given Node.
const internal::VariadicDynCastAllOfMatcher< Decl, VarDecl > varDecl
Matches variable declarations.
const internal::VariadicDynCastAllOfMatcher< Stmt, DeclRefExpr > declRefExpr
Matches expressions that refer to declarations.
const AstTypeMatcher< EnumType > enumType
Matches enum types.
static auto isInUnspecifiedLvalueContext(internal::Matcher< Expr > innerMatcher)
const internal::VariadicOperatorMatcherFunc< 1, 1 > unless
Matches if the provided matcher does not match.
const internal::VariadicDynCastAllOfMatcher< Stmt, ImplicitCastExpr > implicitCastExpr
Matches the implicit cast nodes of Clang's AST.
const AstTypeMatcher< PointerType > pointerType
Matches pointer types, but does not match Objective-C object pointer types.
const internal::VariadicDynCastAllOfMatcher< Decl, BindingDecl > bindingDecl
Matches binding declarations Example matches foo and bar (matcher = bindingDecl()
internal::Matcher< NamedDecl > hasName(StringRef Name)
Matches NamedDecl nodes that have the specified name.
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, CompoundStmt > compoundStmt
Matches compound statements.
static auto hasArrayType()
const internal::ArgumentAdaptingMatcherFunc< internal::ForEachMatcher > forEach
Matches AST nodes that have child AST nodes that match the provided matcher.
const AstTypeMatcher< ArrayType > arrayType
Matches all kinds of arrays.
const internal::VariadicDynCastAllOfMatcher< Stmt, UnaryOperator > unaryOperator
Matches unary operator expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, ArraySubscriptExpr > arraySubscriptExpr
Matches array subscript expressions.
static internal::Matcher< Stmt > isInUnspecifiedUntypedContext(internal::Matcher< Stmt > InnerMatcher)
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXMemberCallExpr > cxxMemberCallExpr
Matches member call expressions.
const internal::VariadicDynCastAllOfMatcher< Decl, CXXConstructorDecl > cxxConstructorDecl
Matches C++ constructor declarations.
const internal::VariadicDynCastAllOfMatcher< Stmt, ArrayInitIndexExpr > arrayInitIndexExpr
The arrayInitIndexExpr consists of two subexpressions: a common expression (the source array) that is...
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator
Matches binary operator expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, ParenExpr > parenExpr
Matches parentheses used in expressions.
const internal::ArgumentAdaptingMatcherFunc< internal::HasMatcher > has
Matches AST nodes that have child AST nodes that match the provided matcher.
const internal::VariadicDynCastAllOfMatcher< Stmt, ExplicitCastExpr > explicitCastExpr
Matches explicit cast expressions.
internal::PolymorphicMatcher< internal::ValueEqualsMatcher, void(internal::AllNodeBaseTypes), ValueT > equals(const ValueT &Value)
Matches literals that are equal to the given value of type ValueT.
const AstTypeMatcher< ConstantArrayType > constantArrayType
Matches C arrays with a specified constant size.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> eachOf
Matches if any of the given matchers matches.
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXConstructExpr > cxxConstructExpr
Matches constructor call expressions (including implicit ones).
static internal::Matcher< Stmt > isInUnspecifiedPointerContext(internal::Matcher< Stmt > InnerMatcher)
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> allOf
Matches if all given matchers match.
const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl
Matches function declarations.
static auto hasPointerType()
const internal::VariadicDynCastAllOfMatcher< Stmt, IntegerLiteral > integerLiteral
Matches integer literals of all sizes / encodings, e.g.
internal::PolymorphicMatcher< internal::HasDeclarationMatcher, void(internal::HasDeclarationSupportedTypes), internal::Matcher< Decl > > hasDeclaration(const internal::Matcher< Decl > &InnerMatcher)
Matches a node if the declaration associated with that node matches the given matcher.
const internal::VariadicDynCastAllOfMatcher< Stmt, DeclStmt > declStmt
Matches declaration statements.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
const internal::VariadicFunction< internal::PolymorphicMatcher< internal::HasAnyOperatorNameMatcher, AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr, CXXRewrittenBinaryOperator, UnaryOperator), std::vector< std::string > >, StringRef, internal::hasAnyOperatorNameFunc > hasAnyOperatorName
Matches operator expressions (binary or unary) that have any of the specified names.
const internal::VariadicDynCastAllOfMatcher< Decl, CXXMethodDecl > cxxMethodDecl
Matches method declarations.
const internal::VariadicDynCastAllOfMatcher< Stmt, CastExpr > castExpr
Matches any cast nodes of Clang's AST.
const internal::VariadicDynCastAllOfMatcher< Stmt, IfStmt > ifStmt
Matches if statements.
bool anyConflict(const llvm::SmallVectorImpl< FixItHint > &FixIts, const SourceManager &SM)
The JSON file list parser is used to communicate input to InstallAPI.
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
std::vector< const VarDecl * > VarGrpTy
const FunctionProtoType * T
Diagnostic wrappers for TextAPI types for error reporting.
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
Wraps an identifier and optional source location for the identifier.
Contains all information for a given match.