15#include "llvm/ADT/SmallVector.h"
23using namespace ast_matchers;
37 internal::ASTMatchFinder *Finder,
38 internal::BoundNodesTreeBuilder *Builder,
39 internal::ASTMatchFinder::BindKind Bind,
40 const bool ignoreUnevaluatedContext)
41 : Matcher(Matcher), Finder(Finder), Builder(Builder), Bind(Bind),
42 Matches(
false), ignoreUnevaluatedContext(ignoreUnevaluatedContext) {}
50 *Builder = ResultBindings;
69 if (isa<FunctionDecl, BlockDecl, ObjCMethodDecl>(
Node))
77 if(ignoreUnevaluatedContext)
79 return VisitorBase::TraverseGenericSelectionExpr(
Node);
84 if(ignoreUnevaluatedContext)
86 return VisitorBase::TraverseUnaryExprOrTypeTraitExpr(
Node);
91 if(ignoreUnevaluatedContext)
93 return VisitorBase::TraverseTypeOfExprTypeLoc(
Node);
98 if(ignoreUnevaluatedContext)
100 return VisitorBase::TraverseDecltypeTypeLoc(
Node);
105 if(ignoreUnevaluatedContext)
107 return VisitorBase::TraverseCXXNoexceptExpr(
Node);
112 if(ignoreUnevaluatedContext)
114 return VisitorBase::TraverseCXXTypeidExpr(
Node);
123 if (isa<LambdaExpr>(
Node))
139 template <
typename T>
bool match(
const T &
Node) {
140 internal::BoundNodesTreeBuilder RecursiveBuilder(*Builder);
143 &RecursiveBuilder)) {
144 ResultBindings.addMatch(RecursiveBuilder);
146 if (Bind != internal::ASTMatchFinder::BK_All)
152 const internal::DynTypedMatcher *
const Matcher;
153 internal::ASTMatchFinder *
const Finder;
154 internal::BoundNodesTreeBuilder *
const Builder;
155 internal::BoundNodesTreeBuilder ResultBindings;
156 const internal::ASTMatchFinder::BindKind Bind;
158 bool ignoreUnevaluatedContext;
167 return hasType(hasCanonicalType(
arrayType()));
171 const DynTypedMatcher &DTM =
static_cast<DynTypedMatcher
>(innerMatcher);
178 const DynTypedMatcher &DTM =
static_cast<DynTypedMatcher
>(innerMatcher);
187 return !Handler->isSafeBufferOptOut(
Node.getBeginLoc());
191 return innerMatcher.matches(*
Node.getSubExpr(), Finder, Builder);
196 return Node.getOpcode() == UnaryOperator::Opcode::UO_PreInc;
206 hasCastKind(CastKind::CK_LValueToRValue),
207 castSubExpr(innerMatcher)),
219static internal::Matcher<Stmt>
229 auto CallArgMatcher =
230 callExpr(forEachArgumentWithParam(InnerMatcher,
234 auto CastOperandMatcher =
236 hasCastKind(CastKind::CK_PointerToBoolean)),
239 auto CompOperandMatcher =
245 auto PtrSubtractionMatcher =
252 eachOf(hasLHS(InnerMatcher),
253 hasRHS(InnerMatcher)));
255 return stmt(
anyOf(CallArgMatcher, CastOperandMatcher, CompOperandMatcher,
256 PtrSubtractionMatcher));
271static internal::Matcher<Stmt>
278 auto IfStmtThen =
ifStmt(hasThen(InnerMatcher));
279 auto IfStmtElse =
ifStmt(hasElse(InnerMatcher));
281 return stmt(
anyOf(CompStmt, IfStmtThen, IfStmtElse));
310#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
316 using Matcher =
decltype(
stmt());
318 Gadget(Kind K) : K(K) {}
322 virtual bool isWarningGadget()
const = 0;
323 virtual const Stmt *getBaseStmt()
const = 0;
328 virtual DeclUseList getClaimedVarUseSites()
const = 0;
330 virtual ~Gadget() =
default;
339class WarningGadget :
public Gadget {
341 WarningGadget(Kind K) : Gadget(K) {}
343 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
344 bool isWarningGadget() const final {
return true; }
351class FixableGadget :
public Gadget {
353 FixableGadget(Kind K) : Gadget(K) {}
355 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
356 bool isWarningGadget() const final {
return false; }
361 virtual std::optional<FixItList> getFixits(
const Strategy &)
const {
370 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
371 getStrategyImplications()
const {
376using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
377using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
381class IncrementGadget :
public WarningGadget {
382 static constexpr const char *
const OpTag =
"op";
387 : WarningGadget(
Kind::Increment),
390 static bool classof(
const Gadget *G) {
391 return G->getKind() == Kind::Increment;
394 static Matcher matcher() {
396 hasOperatorName(
"++"),
401 const UnaryOperator *getBaseStmt()
const override {
return Op; }
403 DeclUseList getClaimedVarUseSites()
const override {
405 if (
const auto *DRE =
410 return std::move(Uses);
416class DecrementGadget :
public WarningGadget {
417 static constexpr const char *
const OpTag =
"op";
422 : WarningGadget(
Kind::Decrement),
425 static bool classof(
const Gadget *G) {
426 return G->getKind() == Kind::Decrement;
429 static Matcher matcher() {
431 hasOperatorName(
"--"),
436 const UnaryOperator *getBaseStmt()
const override {
return Op; }
438 DeclUseList getClaimedVarUseSites()
const override {
439 if (
const auto *DRE =
450class ArraySubscriptGadget :
public WarningGadget {
451 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
456 : WarningGadget(
Kind::ArraySubscript),
459 static bool classof(
const Gadget *G) {
460 return G->getKind() == Kind::ArraySubscript;
463 static Matcher matcher() {
468 hasBase(ignoringParenImpCasts(
471 .bind(ArraySubscrTag));
477 DeclUseList getClaimedVarUseSites()
const override {
478 if (
const auto *DRE =
491class PointerArithmeticGadget :
public WarningGadget {
492 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
493 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
499 : WarningGadget(
Kind::PointerArithmetic),
501 Ptr(Result.
Nodes.getNodeAs<
Expr>(PointerArithmeticPointerTag)) {}
503 static bool classof(
const Gadget *G) {
504 return G->getKind() == Kind::PointerArithmetic;
507 static Matcher matcher() {
508 auto HasIntegerType =
anyOf(hasType(isInteger()), hasType(
enumType()));
510 allOf(hasOperatorName(
"+"),
512 hasLHS(HasIntegerType));
514 allOf(
anyOf(hasOperatorName(
"+"), hasOperatorName(
"-"),
515 hasOperatorName(
"+="), hasOperatorName(
"-=")),
517 hasRHS(HasIntegerType));
520 .bind(PointerArithmeticTag));
523 const Stmt *getBaseStmt()
const override {
return PA; }
525 DeclUseList getClaimedVarUseSites()
const override {
540class PointerAssignmentGadget :
public FixableGadget {
542 static constexpr const char *
const PointerAssignmentTag =
"ptrAssign";
543 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
544 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
551 : FixableGadget(
Kind::PointerAssignment),
556 static bool classof(
const Gadget *G) {
557 return G->getKind() == Kind::PointerAssignment;
560 static Matcher matcher() {
564 bind(PointerAssignRHSTag))),
567 bind(PointerAssignLHSTag))));
573 virtual std::optional<FixItList> getFixits(
const Strategy &S)
const override;
575 virtual const Stmt *getBaseStmt()
const override {
return PA; }
577 virtual DeclUseList getClaimedVarUseSites()
const override {
578 return DeclUseList{PtrLHS, PtrRHS};
581 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
582 getStrategyImplications()
const override {
583 return std::make_pair(cast<VarDecl>(PtrLHS->
getDecl()),
584 cast<VarDecl>(PtrRHS->
getDecl()));
590class UnsafeBufferUsageAttrGadget :
public WarningGadget {
591 constexpr static const char *
const OpTag =
"call_expr";
596 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
599 static bool classof(
const Gadget *G) {
600 return G->getKind() == Kind::UnsafeBufferUsageAttr;
603 static Matcher matcher() {
607 const Stmt *getBaseStmt()
const override {
return Op; }
609 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
615class ULCArraySubscriptGadget :
public FixableGadget {
617 static constexpr const char *
const ULCArraySubscriptTag =
618 "ArraySubscriptUnderULC";
623 : FixableGadget(
Kind::ULCArraySubscript),
625 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
628 static bool classof(
const Gadget *G) {
629 return G->getKind() == Kind::ULCArraySubscript;
632 static Matcher matcher() {
634 auto BaseIsArrayOrPtrDRE =
635 hasBase(ignoringParenImpCasts(
declRefExpr(ArrayOrPtr)));
642 virtual std::optional<FixItList> getFixits(
const Strategy &S)
const override;
644 virtual const Stmt *getBaseStmt()
const override {
return Node; }
646 virtual DeclUseList getClaimedVarUseSites()
const override {
647 if (
const auto *DRE =
648 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts())) {
658class UPCStandalonePointerGadget :
public FixableGadget {
660 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
665 : FixableGadget(
Kind::UPCStandalonePointer),
667 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
670 static bool classof(
const Gadget *G) {
671 return G->getKind() == Kind::UPCStandalonePointer;
674 static Matcher matcher() {
681 virtual std::optional<FixItList> getFixits(
const Strategy &S)
const override;
683 virtual const Stmt *getBaseStmt()
const override {
return Node; }
685 virtual DeclUseList getClaimedVarUseSites()
const override {
690class PointerDereferenceGadget :
public FixableGadget {
691 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
692 static constexpr const char *
const OperatorTag =
"op";
699 : FixableGadget(
Kind::PointerDereference),
704 static bool classof(
const Gadget *G) {
705 return G->getKind() == Kind::PointerDereference;
708 static Matcher matcher() {
711 hasOperatorName(
"*"),
712 has(
expr(ignoringParenImpCasts(
719 DeclUseList getClaimedVarUseSites()
const override {
720 return {BaseDeclRefExpr};
723 virtual const Stmt *getBaseStmt() const final {
return Op; }
725 virtual std::optional<FixItList> getFixits(
const Strategy &S)
const override;
731class UPCAddressofArraySubscriptGadget :
public FixableGadget {
733 static constexpr const char *
const UPCAddressofArraySubscriptTag =
734 "AddressofArraySubscriptUnderUPC";
739 : FixableGadget(
Kind::ULCArraySubscript),
741 UPCAddressofArraySubscriptTag)) {
742 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
745 static bool classof(
const Gadget *G) {
746 return G->getKind() == Kind::UPCAddressofArraySubscript;
749 static Matcher matcher() {
754 .bind(UPCAddressofArraySubscriptTag)))));
757 virtual std::optional<FixItList> getFixits(
const Strategy &)
const override;
759 virtual const Stmt *getBaseStmt()
const override {
return Node; }
761 virtual DeclUseList getClaimedVarUseSites()
const override {
762 const auto *ArraySubst = cast<ArraySubscriptExpr>(
Node->getSubExpr());
764 cast<DeclRefExpr>(ArraySubst->getBase()->IgnoreImpCasts());
774class DeclUseTracker {
775 using UseSetTy = SmallSet<const DeclRefExpr *, 16>;
776 using DefMapTy = DenseMap<const VarDecl *, const DeclStmt *>;
779 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
783 DeclUseTracker() =
default;
784 DeclUseTracker(
const DeclUseTracker &) =
delete;
785 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
786 DeclUseTracker(DeclUseTracker &&) =
default;
787 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
790 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
794 assert(Uses->count(DRE) &&
795 "DRE not found or claimed by multiple matchers!");
800 bool hasUnclaimedUses(
const VarDecl *VD)
const {
802 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
807 void discoverDecl(
const DeclStmt *DS) {
809 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
821 auto It = Defs.find(VD);
822 assert(It != Defs.end() &&
"Definition never discovered!");
844 using MapTy = llvm::DenseMap<const VarDecl *, Kind>;
849 Strategy() =
default;
850 Strategy(
const Strategy &) =
delete;
851 Strategy &operator=(
const Strategy &) =
delete;
852 Strategy(Strategy &&) =
default;
853 Strategy &operator=(Strategy &&) =
default;
855 void set(
const VarDecl *VD, Kind K) { Map[VD] = K; }
858 auto I = Map.find(VD);
860 return Kind::Wontfix;
872 static constexpr const char *
const UPCPreIncrementTag =
873 "PointerPreIncrementUnderUPC";
878 : FixableGadget(Kind::UPCPreIncrement),
880 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
884 return G->getKind() == Kind::UPCPreIncrement;
895 ).bind(UPCPreIncrementTag)))));
898 virtual std::optional<FixItList>
getFixits(
const Strategy &S)
const override;
903 return {dyn_cast<DeclRefExpr>(
Node->getSubExpr())};
910 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
911 static constexpr const char *
const DerefOpTag =
"DerefOp";
912 static constexpr const char *
const AddOpTag =
"AddOp";
913 static constexpr const char *
const OffsetTag =
"Offset";
922 : FixableGadget(Kind::DerefSimplePtrArithFixable),
941 hasOperatorName(
"*"),
942 hasUnaryOperand(ignoringParens(PlusOverPtrAndInteger)))
947 virtual std::optional<FixItList>
getFixits(
const Strategy &
s)
const final;
953 return {BaseDeclRefExpr};
958static std::tuple<FixableGadgetList, WarningGadgetList, DeclUseTracker>
960 bool EmitSuggestions) {
963 FixableGadgetList FixableGadgets;
964 WarningGadgetList WarningGadgets;
965 DeclUseTracker Tracker;
973 [[maybe_unused]]
int numFound = 0;
974#define NEXT ++numFound
977 if (
const auto *DRE = Result.Nodes.getNodeAs<
DeclRefExpr>(
"any_dre")) {
978 Tracker.discoverUse(DRE);
982 if (
const auto *DS = Result.Nodes.getNodeAs<
DeclStmt>(
"any_ds")) {
983 Tracker.discoverDecl(DS);
990#define FIXABLE_GADGET(name) \
991 if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
992 FixableGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
995#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
996#define WARNING_GADGET(name) \
997 if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
998 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
1001#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1003 assert(numFound >= 1 &&
"Gadgets not found in match result!");
1004 assert(numFound <= 1 &&
"Conflicting bind tags in gadgets!");
1009 GadgetFinderCallback CB;
1014 forEachDescendantEvaluatedStmt(
stmt(
anyOf(
1017 allOf(x ## Gadget::matcher().bind(#x), \
1018 notInSafeBufferOptOut(&Handler)),
1019#include
"clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1028 if (EmitSuggestions) {
1034 x ## Gadget::matcher().bind(#x),
1035#include
"clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1039 to(
varDecl())).bind(
"any_dre"),
1056 for (
const auto &G : CB.FixableGadgets) {
1057 for (
const auto *DRE : G->getClaimedVarUseSites()) {
1058 CB.Tracker.claimUse(DRE);
1062 return {std::move(CB.FixableGadgets), std::move(CB.WarningGadgets),
1063 std::move(CB.Tracker)};
1069 return N1->getBeginLoc().getRawEncoding() <
1070 N2->getBeginLoc().getRawEncoding();
1075 std::map<const VarDecl *, std::set<const WarningGadget *>,
1089 for (
auto &G : AllUnsafeOperations) {
1090 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
1092 bool AssociatedWithVarDecl =
false;
1093 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
1094 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1095 result.
byVar[VD].insert(G.get());
1096 AssociatedWithVarDecl =
true;
1100 if (!AssociatedWithVarDecl) {
1101 result.
noVar.push_back(G.get());
1109 std::map<const VarDecl *, std::set<const FixableGadget *>>
byVar;
1115 for (
auto &F : AllFixableOperations) {
1116 DeclUseList DREs = F->getClaimedVarUseSites();
1119 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1120 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
1124 return FixablesForUnsafeVars;
1131 std::vector<const FixItHint *>
All;
1135 std::sort(
All.begin(),
All.end(),
1137 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
1138 H2->RemoveRange.getBegin());
1146 Hint->RemoveRange.getBegin())) {
1158std::optional<FixItList>
1159PointerAssignmentGadget::getFixits(
const Strategy &S)
const {
1160 const auto *LeftVD = cast<VarDecl>(PtrLHS->
getDecl());
1161 const auto *RightVD = cast<VarDecl>(PtrRHS->
getDecl());
1162 switch (S.lookup(LeftVD)) {
1163 case Strategy::Kind::Span:
1164 if (S.lookup(RightVD) == Strategy::Kind::Span)
1166 return std::nullopt;
1167 case Strategy::Kind::Wontfix:
1168 return std::nullopt;
1169 case Strategy::Kind::Iterator:
1170 case Strategy::Kind::Array:
1171 case Strategy::Kind::Vector:
1172 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1174 return std::nullopt;
1178std::optional<FixItList>
1179ULCArraySubscriptGadget::getFixits(
const Strategy &S)
const {
1180 if (
const auto *DRE =
1181 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts()))
1182 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1183 switch (S.lookup(VD)) {
1184 case Strategy::Kind::Span: {
1189 if (
auto ConstVal =
Node->getIdx()->getIntegerConstantExpr(Ctx)) {
1190 if (ConstVal->isNegative())
1191 return std::nullopt;
1192 }
else if (!
Node->getIdx()->getType()->isUnsignedIntegerType())
1193 return std::nullopt;
1197 case Strategy::Kind::Wontfix:
1198 case Strategy::Kind::Iterator:
1199 case Strategy::Kind::Array:
1200 case Strategy::Kind::Vector:
1201 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1204 return std::nullopt;
1207static std::optional<FixItList>
1210std::optional<FixItList>
1211UPCAddressofArraySubscriptGadget::getFixits(
const Strategy &S)
const {
1212 auto DREs = getClaimedVarUseSites();
1213 const auto *VD = cast<VarDecl>(DREs.front()->getDecl());
1215 switch (S.lookup(VD)) {
1216 case Strategy::Kind::Span:
1218 case Strategy::Kind::Wontfix:
1219 case Strategy::Kind::Iterator:
1220 case Strategy::Kind::Array:
1221 case Strategy::Kind::Vector:
1222 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1224 return std::nullopt;
1230 Val.toString(Txt, 10,
true);
1232 Txt.push_back(
'\0');
1237template <
typename NodeTy>
1238static std::optional<SourceLocation>
1247 return std::nullopt;
1251template <
typename NodeTy>
1261 return std::nullopt;
1268 std::optional<SourceLocation> LastCharLoc =
getPastLoc(E,
SM, LangOpts);
1275 return std::nullopt;
1278std::optional<FixItList>
1280 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->
getDecl());
1282 if (VD &&
s.lookup(VD) == Strategy::Kind::Span) {
1286 if (ConstVal->isNegative())
1287 return std::nullopt;
1315 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
1317 return std::nullopt;
1322 std::optional<SourceLocation> AddOpLocation =
1324 std::optional<SourceLocation> DerefOpLocation =
1327 if (!AddOpLocation || !DerefOpLocation)
1328 return std::nullopt;
1338 return std::nullopt;
1341std::optional<FixItList>
1342PointerDereferenceGadget::getFixits(
const Strategy &S)
const {
1344 switch (S.lookup(VD)) {
1345 case Strategy::Kind::Span: {
1353 std::optional<SourceLocation> EndOfOperand =
1358 (*EndOfOperand).getLocWithOffset(1),
"[0]")}};
1362 case Strategy::Kind::Iterator:
1363 case Strategy::Kind::Array:
1364 case Strategy::Kind::Vector:
1365 llvm_unreachable(
"Strategy not implemented yet!");
1366 case Strategy::Kind::Wontfix:
1367 llvm_unreachable(
"Invalid strategy!");
1370 return std::nullopt;
1375std::optional<FixItList> UPCStandalonePointerGadget::getFixits(
const Strategy &S)
1377 const auto VD = cast<VarDecl>(
Node->getDecl());
1378 switch (S.lookup(VD)) {
1379 case Strategy::Kind::Span: {
1383 std::optional<SourceLocation> EndOfOperand =
1388 *EndOfOperand,
".data()")}};
1391 case Strategy::Kind::Wontfix:
1392 case Strategy::Kind::Iterator:
1393 case Strategy::Kind::Array:
1394 case Strategy::Kind::Vector:
1395 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1398 return std::nullopt;
1403static std::optional<FixItList>
1405 const auto *ArraySub = cast<ArraySubscriptExpr>(
Node->getSubExpr());
1406 const auto *DRE = cast<DeclRefExpr>(ArraySub->getBase()->IgnoreImpCasts());
1410 const Expr *Idx = ArraySub->getIdx();
1413 std::stringstream SS;
1414 bool IdxIsLitZero =
false;
1417 if ((*ICE).isZero())
1418 IdxIsLitZero =
true;
1419 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
1421 return std::nullopt;
1425 SS << (*DreString).str() <<
".data()";
1427 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
1429 return std::nullopt;
1431 SS <<
"&" << (*DreString).str() <<
".data()"
1432 <<
"[" << (*IndexString).str() <<
"]";
1442 if (DREs.size() != 1)
1443 return std::nullopt;
1445 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
1446 if (S.lookup(VD) == Strategy::Kind::Span) {
1448 std::stringstream SS;
1450 StringRef varName = VD->
getName();
1454 SS <<
"(" << varName.data() <<
" = " << varName.data()
1455 <<
".subspan(1)).data()";
1456 std::optional<SourceLocation> PreIncLocation =
1458 if (!PreIncLocation)
1459 return std::nullopt;
1466 return std::nullopt;
1484 const StringRef UserFillPlaceHolder) {
1492 if (Init->isNullPointerConstant(
1493 std::remove_const_t<ASTContext &>(Ctx),
1497 NPC_ValueDependentIsNotNull)) {
1498 std::optional<SourceLocation> InitLocation =
1503 SourceRange SR(Init->getBeginLoc(), *InitLocation);
1509 std::string ExtentText = UserFillPlaceHolder.data();
1510 StringRef One =
"1";
1515 if (
auto CxxNew = dyn_cast<CXXNewExpr>(Init->IgnoreImpCasts())) {
1520 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
1521 if (!Ext->HasSideEffects(Ctx)) {
1522 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
1525 ExtentText = *ExtentString;
1527 }
else if (!CxxNew->isArray())
1532 Init->IgnoreImpCasts()->getType())) {
1540 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(Init->IgnoreImpCasts()))
1541 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
1542 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
1549 std::optional<SourceLocation> LocPassInit =
getPastLoc(Init,
SM, LangOpts);
1554 StrBuffer.append(
", ");
1555 StrBuffer.append(ExtentText);
1556 StrBuffer.append(
"}");
1575 const StringRef UserFillPlaceHolder) {
1577 assert(!SpanEltT.
isNull() &&
"Trying to fix a non-pointer type variable!");
1580 std::optional<SourceLocation>
1585 FixItList InitFixIts =
1588 if (InitFixIts.empty())
1592 ReplacementLastLoc = Init->getBeginLoc().getLocWithOffset(-1);
1593 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts.begin()),
1594 std::make_move_iterator(InitFixIts.end()));
1600 raw_svector_ostream OS(Replacement);
1604 if (!ReplacementLastLoc)
1613 const DeclUseTracker &Tracker,
1616 const DeclStmt *DS = Tracker.lookupDecl(VD);
1617 assert(DS &&
"Fixing non-local variables not implemented yet!");
1632 const DeclUseTracker &Tracker,
1636 case Strategy::Kind::Span: {
1641 case Strategy::Kind::Iterator:
1642 case Strategy::Kind::Array:
1643 case Strategy::Kind::Vector:
1644 llvm_unreachable(
"Strategy not implemented yet!");
1645 case Strategy::Kind::Wontfix:
1646 llvm_unreachable(
"Invalid strategy!");
1648 llvm_unreachable(
"Unknown strategy!");
1656 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
1658 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
1668 for (
const auto &F : FixablesForUnsafeVars.
byVar.find(Var)->second) {
1669 std::optional<FixItList> Fixits = F->getFixits(S);
1677static std::map<const VarDecl *, FixItList>
1679 const DeclUseTracker &Tracker,
const ASTContext &Ctx,
1682 std::map<const VarDecl *, FixItList> FixItsForVariable;
1683 for (
const auto &[VD, Fixables] : FixablesForUnsafeVars.
byVar) {
1684 const Strategy::Kind ReplacementTypeForVD = S.lookup(VD);
1685 FixItsForVariable[VD] =
1686 fixVariable(VD, ReplacementTypeForVD, Tracker, Ctx, Handler);
1689 if (FixItsForVariable[VD].empty()) {
1690 FixItsForVariable.erase(VD);
1693 bool ImpossibleToFix =
false;
1695 for (
const auto &F : Fixables) {
1696 std::optional<FixItList> Fixits = F->getFixits(S);
1698 ImpossibleToFix =
true;
1701 const FixItList CorrectFixes = Fixits.value();
1702 FixItsForVD.insert(FixItsForVD.end(), CorrectFixes.begin(),
1703 CorrectFixes.end());
1707 if (ImpossibleToFix) {
1708 FixItsForVariable.erase(VD);
1712 const auto VarGroupForVD = VarGrpMap.find(VD);
1713 if (VarGroupForVD != VarGrpMap.end()) {
1714 for (
const VarDecl *
V : VarGroupForVD->second) {
1719 ImpossibleToFix =
true;
1724 if (ImpossibleToFix) {
1725 FixItsForVariable.erase(VD);
1726 for (
const VarDecl *
V : VarGroupForVD->second) {
1727 FixItsForVariable.erase(
V);
1732 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
1733 FixItsForVD.begin(), FixItsForVD.end());
1739 FixItsForVariable.erase(VD);
1744 for (
auto VD : FixItsForVariable) {
1745 const auto VarGroupForVD = VarGrpMap.find(VD.first);
1746 const Strategy::Kind ReplacementTypeForVD = S.lookup(VD.first);
1747 if (VarGroupForVD != VarGrpMap.end()) {
1748 for (
const VarDecl * Var : VarGroupForVD->second) {
1749 if (Var == VD.first) {
1754 if (FixItsForVariable.find(Var) == FixItsForVariable.end()) {
1755 GroupFix =
fixVariable(Var, ReplacementTypeForVD, Tracker,
1758 GroupFix = FixItsForVariable[Var];
1761 for (
auto Fix : GroupFix) {
1762 FixItsForVariable[VD.first].push_back(Fix);
1767 return FixItsForVariable;
1774 for (
const VarDecl *VD : UnsafeVars) {
1775 S.set(VD, Strategy::Kind::Span);
1782 bool EmitSuggestions) {
1787 auto [FixableGadgets, WarningGadgets, Tracker] =
1790 if (!EmitSuggestions) {
1794 for (
const auto &G : WarningGadgets) {
1801 assert(FixableGadgets.size() == 0 &&
1802 "Fixable gadgets found but suggestions not requested!");
1809 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
1813 for (
auto it = FixablesForAllVars.
byVar.cbegin();
1814 it != FixablesForAllVars.
byVar.cend();) {
1816 if (!it->first->isLocalVarDecl() || Tracker.hasUnclaimedUses(it->first)) {
1817 it = FixablesForAllVars.
byVar.erase(it);
1824 for (
const auto &[VD, ignore] : FixablesForAllVars.
byVar)
1825 UnsafeVars.push_back(VD);
1828 using DepMapTy = DenseMap<const VarDecl *, std::set<const VarDecl *>>;
1829 DepMapTy DependenciesMap{};
1830 DepMapTy PtrAssignmentGraph{};
1832 for (
auto it : FixablesForAllVars.
byVar) {
1833 for (
const FixableGadget *fixable : it.second) {
1834 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
1835 fixable->getStrategyImplications();
1837 std::pair<const VarDecl *, const VarDecl *> Impl = ImplPair.value();
1838 PtrAssignmentGraph[Impl.first].insert(Impl.second);
1860 std::set<const VarDecl *> VisitedVarsDirected{};
1861 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
1862 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
1864 std::queue<const VarDecl*> QueueDirected{};
1865 QueueDirected.push(Var);
1866 while(!QueueDirected.empty()) {
1867 const VarDecl* CurrentVar = QueueDirected.front();
1868 QueueDirected.pop();
1869 VisitedVarsDirected.insert(CurrentVar);
1870 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
1871 for (
const VarDecl *Adj : AdjacentNodes) {
1872 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
1873 QueueDirected.push(Adj);
1875 DependenciesMap[Var].insert(Adj);
1876 DependenciesMap[Adj].insert(Var);
1884 std::set<const VarDecl *> VisitedVars{};
1885 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
1886 if (VisitedVars.find(Var) == VisitedVars.end()) {
1887 std::vector<const VarDecl *> VarGroup{};
1889 std::queue<const VarDecl*> Queue{};
1891 while(!Queue.empty()) {
1892 const VarDecl* CurrentVar = Queue.front();
1894 VisitedVars.insert(CurrentVar);
1895 VarGroup.push_back(CurrentVar);
1896 auto AdjacentNodes = DependenciesMap[CurrentVar];
1897 for (
const VarDecl *Adj : AdjacentNodes) {
1898 if (VisitedVars.find(Adj) == VisitedVars.end()) {
1903 for (
const VarDecl *
V : VarGroup) {
1904 if (UnsafeOps.
byVar.find(
V) != UnsafeOps.
byVar.end()) {
1905 VariableGroupsMap[
V] = VarGroup;
1912 FixItsForVariableGroup =
getFixIts(FixablesForAllVars, NaiveStrategy, Tracker,
1917 for (
const auto &G : UnsafeOps.
noVar) {
1921 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
1922 auto FixItsIt = FixItsForVariableGroup.find(VD);
1924 FixItsIt != FixItsForVariableGroup.end()
1925 ? std::move(FixItsIt->second)
1927 for (
const auto &G : WarningGadgets) {
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::DenseMap< Stmt *, Stmt * > MapTy
Defines the clang::Preprocessor interface.
static bool hasAttr(const FunctionDecl *D, bool IgnoreImplicitAttr)
static std::optional< FixItList > fixUPCAddressofArraySubscriptWithSpan(const UnaryOperator *Node)
static std::optional< StringRef > getExprText(const Expr *E, const SourceManager &SM, const LangOptions &LangOpts)
static FixItList fixVariableWithSpan(const VarDecl *VD, const DeclUseTracker &Tracker, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static WarningGadgetSets groupWarningGadgetsByVar(const WarningGadgetList &AllUnsafeOperations)
static FixItList fixVarDeclWithSpan(const VarDecl *D, const ASTContext &Ctx, const StringRef UserFillPlaceHolder)
static std::map< const VarDecl *, FixItList > getFixIts(FixableGadgetSets &FixablesForUnsafeVars, const Strategy &S, const DeclUseTracker &Tracker, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler, const DefMapTy &VarGrpMap)
static std::optional< SourceLocation > getEndCharLoc(const NodeTy *Node, const SourceManager &SM, const LangOptions &LangOpts)
#define FIXABLE_GADGET(name)
static FixItList fixVariable(const VarDecl *VD, Strategy::Kind K, const DeclUseTracker &Tracker, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static bool impossibleToFixForVar(const FixableGadgetSets &FixablesForUnsafeVars, const Strategy &S, const VarDecl *Var)
#define WARNING_GADGET(name)
static std::optional< SourceLocation > getPastLoc(const NodeTy *Node, const SourceManager &SM, const LangOptions &LangOpts)
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 Strategy getNaiveStrategy(const llvm::SmallVectorImpl< const VarDecl * > &UnsafeVars)
static bool overlapWithMacro(const FixItList &FixIts)
static FixItList populateInitializerFixItWithSpan(const Expr *Init, const ASTContext &Ctx, const StringRef UserFillPlaceHolder)
static FixableGadgetSets groupFixablesByVar(FixableGadgetList &&AllFixableOperations)
static std::string getAPIntText(APInt Val)
__device__ __2f16 float bool s
DerefSimplePtrArithFixableGadget(const MatchFinder::MatchResult &Result)
virtual const Stmt * getBaseStmt() const final
virtual std::optional< FixItList > getFixits(const Strategy &s) const final
virtual DeclUseList getClaimedVarUseSites() const final
virtual const Stmt * getBaseStmt() const override
virtual DeclUseList getClaimedVarUseSites() const override
static bool classof(const Gadget *G)
UPCPreIncrementGadget(const MatchFinder::MatchResult &Result)
virtual std::optional< FixItList > getFixits(const Strategy &S) const override
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
const LangOptions & getLangOpts() const
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
A builtin binary operation expression such as "x + y" or "x <= y".
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...
Represents a character-granular source range.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getEnd() const
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.
ASTContext & getASTContext() const LLVM_READONLY
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
SourceLocation getBeginLoc() const LLVM_READONLY
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.
This represents one expression.
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc=nullptr, bool isEvaluated=true) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
NullPointerConstantValueDependence
Enumeration used to describe how isNullPointerConstant() should cope with value-dependent expressions...
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 C11 generic selection.
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 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.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
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...
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.
Stmt - This represents one statement.
SourceLocation getBeginLoc() const LLVM_READONLY
bool isPointerType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
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
The interface that lets the caller handle unsafe buffer usage analysis results by overriding this cla...
virtual void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl)=0
Invoked when an unsafe operation over raw pointers is found.
virtual void handleUnsafeVariableGroup(const VarDecl *Variable, const DefMapTy &VarGrpMap, FixItList &&Fixes)=0
Invoked when a fix is suggested against a variable.
virtual std::string getUserFillPlaceHolder(StringRef HintTextToUser="placeholder") const
Returns the text indicating that the user needs to provide input there:
Represents a variable declaration or definition.
VarDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
const Expr * getInit() const
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
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< 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, BinaryOperator > binaryOperator
Matches binary operator expressions.
const internal::ArgumentAdaptingMatcherFunc< internal::HasMatcher > has
Matches AST nodes that have child AST nodes that match the provided matcher.
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 internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> eachOf
Matches if any of the given matchers matches.
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.
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< 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)
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
llvm::DenseMap< const VarDecl *, std::vector< const VarDecl * > > DefMapTy
YAML serialization mapping.
bool operator()(const NodeTy *N1, const NodeTy *N2) const
std::map< const VarDecl *, std::set< const FixableGadget * > > byVar
std::map< const VarDecl *, std::set< const WarningGadget * >, CompareNode< VarDecl > > byVar
llvm::SmallVector< const WarningGadget *, 16 > noVar
Contains all information for a given match.