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;
502 virtual DeclUseList getClaimedVarUseSites()
const = 0;
504 virtual ~Gadget() =
default;
512class WarningGadget :
public Gadget {
514 WarningGadget(Kind K) : Gadget(K) {}
516 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
517 bool isWarningGadget() const final {
return true; }
520 bool IsRelatedToDecl,
528class FixableGadget :
public Gadget {
530 FixableGadget(Kind K) : Gadget(K) {}
532 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
533 bool isWarningGadget() const final {
return false; }
538 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
548 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
549 getStrategyImplications()
const {
554static auto toSupportedVariable() {
return to(
varDecl()); }
556using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
557using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
561class IncrementGadget :
public WarningGadget {
562 static constexpr const char *
const OpTag =
"op";
567 : WarningGadget(
Kind::Increment),
570 static bool classof(
const Gadget *G) {
571 return G->getKind() == Kind::Increment;
574 static Matcher matcher() {
582 bool IsRelatedToDecl,
588 DeclUseList getClaimedVarUseSites()
const override {
590 if (
const auto *DRE =
595 return std::move(Uses);
601class DecrementGadget :
public WarningGadget {
602 static constexpr const char *
const OpTag =
"op";
607 : WarningGadget(
Kind::Decrement),
610 static bool classof(
const Gadget *G) {
611 return G->getKind() == Kind::Decrement;
614 static Matcher matcher() {
622 bool IsRelatedToDecl,
628 DeclUseList getClaimedVarUseSites()
const override {
629 if (
const auto *DRE =
640class ArraySubscriptGadget :
public WarningGadget {
641 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
646 : WarningGadget(
Kind::ArraySubscript),
649 static bool classof(
const Gadget *G) {
650 return G->getKind() == Kind::ArraySubscript;
653 static Matcher matcher() {
656 hasBase(ignoringParenImpCasts(
659 isSafeArraySubscript(),
663 ))).bind(ArraySubscrTag));
668 bool IsRelatedToDecl,
674 DeclUseList getClaimedVarUseSites()
const override {
675 if (
const auto *DRE =
688class PointerArithmeticGadget :
public WarningGadget {
689 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
690 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
696 : WarningGadget(
Kind::PointerArithmetic),
698 Ptr(Result.
Nodes.getNodeAs<
Expr>(PointerArithmeticPointerTag)) {}
700 static bool classof(
const Gadget *G) {
701 return G->getKind() == Kind::PointerArithmetic;
704 static Matcher matcher() {
705 auto HasIntegerType =
anyOf(hasType(isInteger()), hasType(
enumType()));
707 allOf(hasOperatorName(
"+"),
709 hasLHS(HasIntegerType));
711 allOf(
anyOf(hasOperatorName(
"+"), hasOperatorName(
"-"),
712 hasOperatorName(
"+="), hasOperatorName(
"-=")),
714 hasRHS(HasIntegerType));
717 .bind(PointerArithmeticTag));
721 bool IsRelatedToDecl,
727 DeclUseList getClaimedVarUseSites()
const override {
738class SpanTwoParamConstructorGadget :
public WarningGadget {
739 static constexpr const char *
const SpanTwoParamConstructorTag =
740 "spanTwoParamConstructor";
745 : WarningGadget(
Kind::SpanTwoParamConstructor),
747 SpanTwoParamConstructorTag)) {}
749 static bool classof(
const Gadget *G) {
750 return G->getKind() == Kind::SpanTwoParamConstructor;
753 static Matcher matcher() {
756 parameterCountIs(2)));
759 unless(isSafeSpanTwoParamConstruct()))
760 .bind(SpanTwoParamConstructorTag));
764 bool IsRelatedToDecl,
770 DeclUseList getClaimedVarUseSites()
const override {
773 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->
getArg(0))) {
774 if (isa<VarDecl>(DRE->
getDecl()))
785class PointerInitGadget :
public FixableGadget {
787 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
788 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
794 : FixableGadget(
Kind::PointerInit),
795 PtrInitLHS(Result.
Nodes.getNodeAs<
VarDecl>(PointerInitLHSTag)),
798 static bool classof(
const Gadget *G) {
799 return G->getKind() == Kind::PointerInit;
802 static Matcher matcher() {
803 auto PtrInitStmt =
declStmt(hasSingleDecl(
804 varDecl(hasInitializer(ignoringImpCasts(
806 .bind(PointerInitRHSTag))))
807 .bind(PointerInitLHSTag)));
809 return stmt(PtrInitStmt);
812 virtual std::optional<FixItList>
818 virtual DeclUseList getClaimedVarUseSites()
const override {
819 return DeclUseList{PtrInitRHS};
822 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
823 getStrategyImplications()
const override {
824 return std::make_pair(PtrInitLHS, cast<VarDecl>(PtrInitRHS->
getDecl()));
833class PtrToPtrAssignmentGadget :
public FixableGadget {
835 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
836 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
842 : FixableGadget(
Kind::PtrToPtrAssignment),
846 static bool classof(
const Gadget *G) {
847 return G->getKind() == Kind::PtrToPtrAssignment;
850 static Matcher matcher() {
852 allOf(hasOperatorName(
"="),
853 hasRHS(ignoringParenImpCasts(
855 .bind(PointerAssignRHSTag))),
857 .bind(PointerAssignLHSTag))));
862 virtual std::optional<FixItList>
866 virtual DeclUseList getClaimedVarUseSites()
const override {
867 return DeclUseList{PtrLHS, PtrRHS};
870 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
871 getStrategyImplications()
const override {
872 return std::make_pair(cast<VarDecl>(PtrLHS->
getDecl()),
873 cast<VarDecl>(PtrRHS->
getDecl()));
882class CArrayToPtrAssignmentGadget :
public FixableGadget {
884 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
885 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
891 : FixableGadget(
Kind::CArrayToPtrAssignment),
895 static bool classof(
const Gadget *G) {
896 return G->getKind() == Kind::CArrayToPtrAssignment;
899 static Matcher matcher() {
901 allOf(hasOperatorName(
"="),
902 hasRHS(ignoringParenImpCasts(
904 toSupportedVariable())
905 .bind(PointerAssignRHSTag))),
907 .bind(PointerAssignLHSTag))));
912 virtual std::optional<FixItList>
916 virtual DeclUseList getClaimedVarUseSites()
const override {
917 return DeclUseList{PtrLHS, PtrRHS};
920 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
921 getStrategyImplications()
const override {
928class UnsafeBufferUsageAttrGadget :
public WarningGadget {
929 constexpr static const char *
const OpTag =
"call_expr";
934 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
937 static bool classof(
const Gadget *G) {
938 return G->getKind() == Kind::UnsafeBufferUsageAttr;
941 static Matcher matcher() {
942 auto HasUnsafeFnDecl =
948 bool IsRelatedToDecl,
954 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
960class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
961 constexpr static const char *
const OpTag =
"cxx_construct_expr";
966 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
969 static bool classof(
const Gadget *G) {
970 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
973 static Matcher matcher() {
974 auto HasUnsafeCtorDecl =
977 auto HasTwoParamSpanCtorDecl = SpanTwoParamConstructorGadget::matcher();
984 bool IsRelatedToDecl,
990 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
997class DataInvocationGadget :
public WarningGadget {
998 constexpr static const char *
const OpTag =
"data_invocation_expr";
1003 : WarningGadget(
Kind::DataInvocation),
1006 static bool classof(
const Gadget *G) {
1007 return G->getKind() == Kind::DataInvocation;
1010 static Matcher matcher() {
1019 bool IsRelatedToDecl,
1025 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1031class ULCArraySubscriptGadget :
public FixableGadget {
1033 static constexpr const char *
const ULCArraySubscriptTag =
1034 "ArraySubscriptUnderULC";
1039 : FixableGadget(
Kind::ULCArraySubscript),
1041 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
1044 static bool classof(
const Gadget *G) {
1045 return G->getKind() == Kind::ULCArraySubscript;
1048 static Matcher matcher() {
1050 auto BaseIsArrayOrPtrDRE = hasBase(
1051 ignoringParenImpCasts(
declRefExpr(ArrayOrPtr, toSupportedVariable())));
1058 virtual std::optional<FixItList>
1062 virtual DeclUseList getClaimedVarUseSites()
const override {
1063 if (
const auto *DRE =
1064 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts())) {
1074class UPCStandalonePointerGadget :
public FixableGadget {
1076 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
1081 : FixableGadget(
Kind::UPCStandalonePointer),
1083 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
1086 static bool classof(
const Gadget *G) {
1087 return G->getKind() == Kind::UPCStandalonePointer;
1090 static Matcher matcher() {
1092 auto target =
expr(ignoringParenImpCasts(
1094 .bind(DeclRefExprTag)));
1098 virtual std::optional<FixItList>
1102 virtual DeclUseList getClaimedVarUseSites()
const override {
return {
Node}; }
1105class PointerDereferenceGadget :
public FixableGadget {
1106 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
1107 static constexpr const char *
const OperatorTag =
"op";
1114 : FixableGadget(
Kind::PointerDereference),
1119 static bool classof(
const Gadget *G) {
1120 return G->getKind() == Kind::PointerDereference;
1123 static Matcher matcher() {
1126 hasOperatorName(
"*"),
1127 has(
expr(ignoringParenImpCasts(
1128 declRefExpr(toSupportedVariable()).bind(BaseDeclRefExprTag)))))
1134 DeclUseList getClaimedVarUseSites()
const override {
1135 return {BaseDeclRefExpr};
1138 virtual std::optional<FixItList>
1146class UPCAddressofArraySubscriptGadget :
public FixableGadget {
1148 static constexpr const char *
const UPCAddressofArraySubscriptTag =
1149 "AddressofArraySubscriptUnderUPC";
1154 : FixableGadget(
Kind::ULCArraySubscript),
1156 UPCAddressofArraySubscriptTag)) {
1157 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
1160 static bool classof(
const Gadget *G) {
1161 return G->getKind() == Kind::UPCAddressofArraySubscript;
1164 static Matcher matcher() {
1167 hasOperatorName(
"&"),
1169 ignoringParenImpCasts(
declRefExpr(toSupportedVariable()))))))
1170 .bind(UPCAddressofArraySubscriptTag)))));
1173 virtual std::optional<FixItList>
1177 virtual DeclUseList getClaimedVarUseSites()
const override {
1178 const auto *ArraySubst = cast<ArraySubscriptExpr>(
Node->getSubExpr());
1180 cast<DeclRefExpr>(ArraySubst->getBase()->IgnoreParenImpCasts());
1190class DeclUseTracker {
1191 using UseSetTy = SmallSet<const DeclRefExpr *, 16>;
1192 using DefMapTy = DenseMap<const VarDecl *, const DeclStmt *>;
1195 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
1199 DeclUseTracker() =
default;
1200 DeclUseTracker(
const DeclUseTracker &) =
delete;
1201 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
1202 DeclUseTracker(DeclUseTracker &&) =
default;
1203 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
1206 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
1210 assert(Uses->count(DRE) &&
1211 "DRE not found or claimed by multiple matchers!");
1216 bool hasUnclaimedUses(
const VarDecl *VD)
const {
1218 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
1223 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
1225 for (
auto use : *Uses) {
1227 ReturnSet.insert(use);
1233 void discoverDecl(
const DeclStmt *DS) {
1235 if (
const auto *VD = dyn_cast<VarDecl>(
D)) {
1247 return Defs.lookup(VD);
1256 static constexpr const char *
const UPCPreIncrementTag =
1257 "PointerPreIncrementUnderUPC";
1262 : FixableGadget(Kind::UPCPreIncrement),
1264 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
1268 return G->getKind() == Kind::UPCPreIncrement;
1278 hasUnaryOperand(
declRefExpr(toSupportedVariable())))
1279 .bind(UPCPreIncrementTag)))));
1282 virtual std::optional<FixItList>
1287 return {dyn_cast<DeclRefExpr>(
Node->getSubExpr())};
1295 static constexpr const char *
const UUCAddAssignTag =
1296 "PointerAddAssignUnderUUC";
1297 static constexpr const char *
const OffsetTag =
"Offset";
1300 const Expr *Offset =
nullptr;
1304 : FixableGadget(Kind::UUCAddAssign),
1306 Offset(Result.
Nodes.getNodeAs<
Expr>(OffsetTag)) {
1307 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
1311 return G->getKind() == Kind::UUCAddAssign;
1321 toSupportedVariable())),
1322 hasRHS(
expr().bind(OffsetTag)))
1323 .bind(UUCAddAssignTag)))));
1327 virtual std::optional<FixItList>
1332 return {dyn_cast<DeclRefExpr>(
Node->getLHS())};
1339 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
1340 static constexpr const char *
const DerefOpTag =
"DerefOp";
1341 static constexpr const char *
const AddOpTag =
"AddOp";
1342 static constexpr const char *
const OffsetTag =
"Offset";
1351 : FixableGadget(Kind::DerefSimplePtrArithFixable),
1361 ignoringImpCasts(
declRefExpr(toSupportedVariable()).
1362 bind(BaseDeclRefExprTag)));
1363 auto PlusOverPtrAndInteger =
expr(
anyOf(
1371 hasOperatorName(
"*"),
1372 hasUnaryOperand(ignoringParens(PlusOverPtrAndInteger)))
1377 virtual std::optional<FixItList>
1384 return {BaseDeclRefExpr};
1389static std::tuple<FixableGadgetList, WarningGadgetList, DeclUseTracker>
1391 bool EmitSuggestions) {
1394 FixableGadgetList FixableGadgets;
1395 WarningGadgetList WarningGadgets;
1396 DeclUseTracker Tracker;
1404 [[maybe_unused]]
int numFound = 0;
1405#define NEXT ++numFound
1408 if (
const auto *DRE = Result.Nodes.getNodeAs<
DeclRefExpr>(
"any_dre")) {
1409 Tracker.discoverUse(DRE);
1413 if (
const auto *DS = Result.Nodes.getNodeAs<
DeclStmt>(
"any_ds")) {
1414 Tracker.discoverDecl(DS);
1421#define FIXABLE_GADGET(name) \
1422 if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
1423 FixableGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
1426#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1427#define WARNING_GADGET(name) \
1428 if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
1429 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
1432#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1434 assert(numFound >= 1 &&
"Gadgets not found in match result!");
1435 assert(numFound <= 1 &&
"Conflicting bind tags in gadgets!");
1440 GadgetFinderCallback CB;
1445 forEachDescendantEvaluatedStmt(
stmt(
anyOf(
1448 allOf(x ## Gadget::matcher().bind(#x), \
1449 notInSafeBufferOptOut(&Handler)),
1451 allOf(x ## Gadget::matcher().bind(#x), \
1452 notInSafeBufferOptOut(&Handler), \
1453 unless(ignoreUnsafeBufferInContainer(&Handler))),
1454#include
"clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1463 if (EmitSuggestions) {
1469 x ## Gadget::matcher().bind(#x),
1470#include
"clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1487 return {std::move(CB.FixableGadgets), std::move(CB.WarningGadgets),
1488 std::move(CB.Tracker)};
1494 return N1->getBeginLoc().getRawEncoding() <
1495 N2->getBeginLoc().getRawEncoding();
1500 std::map<const VarDecl *, std::set<const WarningGadget *>,
1514 for (
auto &G : AllUnsafeOperations) {
1515 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
1517 bool AssociatedWithVarDecl =
false;
1518 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
1519 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1520 result.
byVar[VD].insert(G.get());
1521 AssociatedWithVarDecl =
true;
1525 if (!AssociatedWithVarDecl) {
1526 result.
noVar.push_back(G.get());
1534 std::map<const VarDecl *, std::set<const FixableGadget *>,
1544 for (
auto &F : AllFixableOperations) {
1545 DeclUseList DREs = F->getClaimedVarUseSites();
1548 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1549 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
1553 return FixablesForUnsafeVars;
1560 std::vector<const FixItHint *> All;
1564 std::sort(All.begin(), All.end(),
1566 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
1567 H2->RemoveRange.getBegin());
1575 Hint->RemoveRange.getBegin())) {
1587std::optional<FixItList>
1588PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
1589 const auto *LeftVD = cast<VarDecl>(PtrLHS->
getDecl());
1590 const auto *RightVD = cast<VarDecl>(PtrRHS->
getDecl());
1591 switch (S.lookup(LeftVD)) {
1592 case FixitStrategy::Kind::Span:
1593 if (S.lookup(RightVD) == FixitStrategy::Kind::Span)
1595 return std::nullopt;
1596 case FixitStrategy::Kind::Wontfix:
1597 return std::nullopt;
1598 case FixitStrategy::Kind::Iterator:
1599 case FixitStrategy::Kind::Array:
1600 return std::nullopt;
1601 case FixitStrategy::Kind::Vector:
1602 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1604 return std::nullopt;
1611std::optional<FixItList>
1612CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
1613 const auto *LeftVD = cast<VarDecl>(PtrLHS->
getDecl());
1614 const auto *RightVD = cast<VarDecl>(PtrRHS->
getDecl());
1631 if (S.lookup(LeftVD) == FixitStrategy::Kind::Span) {
1632 if (S.lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
1635 }
else if (S.lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
1636 if (S.lookup(RightVD) == FixitStrategy::Kind::Array) {
1640 return std::nullopt;
1643std::optional<FixItList>
1645 const auto *LeftVD = PtrInitLHS;
1646 const auto *RightVD = cast<VarDecl>(PtrInitRHS->
getDecl());
1647 switch (S.lookup(LeftVD)) {
1648 case FixitStrategy::Kind::Span:
1649 if (S.lookup(RightVD) == FixitStrategy::Kind::Span)
1651 return std::nullopt;
1652 case FixitStrategy::Kind::Wontfix:
1653 return std::nullopt;
1654 case FixitStrategy::Kind::Iterator:
1655 case FixitStrategy::Kind::Array:
1656 return std::nullopt;
1657 case FixitStrategy::Kind::Vector:
1658 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1660 return std::nullopt;
1666 if (ConstVal->isNegative())
1673std::optional<FixItList>
1674ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
1675 if (
const auto *DRE =
1676 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts()))
1677 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1678 switch (S.lookup(VD)) {
1679 case FixitStrategy::Kind::Span: {
1686 return std::nullopt;
1690 case FixitStrategy::Kind::Array:
1692 case FixitStrategy::Kind::Wontfix:
1693 case FixitStrategy::Kind::Iterator:
1694 case FixitStrategy::Kind::Vector:
1695 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1698 return std::nullopt;
1701static std::optional<FixItList>
1704std::optional<FixItList>
1705UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
1706 auto DREs = getClaimedVarUseSites();
1707 const auto *VD = cast<VarDecl>(DREs.front()->getDecl());
1709 switch (S.lookup(VD)) {
1710 case FixitStrategy::Kind::Span:
1712 case FixitStrategy::Kind::Wontfix:
1713 case FixitStrategy::Kind::Iterator:
1714 case FixitStrategy::Kind::Array:
1715 return std::nullopt;
1716 case FixitStrategy::Kind::Vector:
1717 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1719 return std::nullopt;
1724 static const char *
const EOL =
"\n";
1730 std::string
s = std::string(
"<# ");
1731 s += HintTextToUser;
1737template <
typename NodeTy>
1738static std::optional<SourceLocation>
1747 return std::nullopt;
1751template <
typename NodeTy>
1759 return std::nullopt;
1766 std::optional<SourceLocation> LastCharLoc =
getPastLoc(
E,
SM, LangOpts);
1773 return std::nullopt;
1786 return std::nullopt;
1798static std::optional<StringRef>
1807 return std::nullopt;
1808 return getRangeText({ParmIdentBeginLoc, ParmIdentEndLoc},
SM, LangOpts);
1821 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
1822 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
1823 VD->getBeginLoc())) &&
1824 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
1825 At->getRange().getBegin()));
1829 AttrRangeOverlapping;
1853static std::optional<std::string>
1856 std::optional<Qualifiers> *QualifiersToAppend) {
1861 "Expecting a VarDecl of type of pointer to object type");
1870 case TypeLoc::ConstantArray:
1871 case TypeLoc::IncompleteArray:
1872 case TypeLoc::VariableArray:
1873 case TypeLoc::DependentSizedArray:
1874 case TypeLoc::Decayed:
1875 assert(isa<ParmVarDecl>(VD) &&
"An array type shall not be treated as a "
1876 "pointer type unless it decays.");
1879 case TypeLoc::Pointer:
1883 return std::nullopt;
1888 return std::nullopt;
1896 return std::nullopt;
1903 if (!PteEndOfTokenLoc.
isValid())
1906 return std::nullopt;
1907 if (!
SM.isBeforeInTranslationUnit(PteEndOfTokenLoc, IdentLoc)) {
1914 return std::nullopt;
1949 std::optional<Qualifiers> Quals = std::nullopt) {
1950 const char *
const SpanOpen =
"std::span<";
1953 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
1954 return SpanOpen + EltTyText.str() +
'>';
1957std::optional<FixItList>
1959 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->
getDecl());
1961 if (VD &&
s.lookup(VD) == FixitStrategy::Kind::Span) {
1965 if (ConstVal->isNegative())
1966 return std::nullopt;
1994 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
1996 return std::nullopt;
2001 std::optional<SourceLocation> AddOpLocation =
2003 std::optional<SourceLocation> DerefOpLocation =
2006 if (!AddOpLocation || !DerefOpLocation)
2007 return std::nullopt;
2017 return std::nullopt;
2020std::optional<FixItList>
2021PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
2023 switch (S.lookup(VD)) {
2024 case FixitStrategy::Kind::Span: {
2032 if (
auto LocPastOperand =
2039 case FixitStrategy::Kind::Iterator:
2040 case FixitStrategy::Kind::Array:
2041 return std::nullopt;
2042 case FixitStrategy::Kind::Vector:
2043 llvm_unreachable(
"FixitStrategy not implemented yet!");
2044 case FixitStrategy::Kind::Wontfix:
2045 llvm_unreachable(
"Invalid strategy!");
2048 return std::nullopt;
2055 std::optional<SourceLocation> EndOfOperand =
2061 return std::nullopt;
2066std::optional<FixItList>
2067UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
2068 const auto VD = cast<VarDecl>(
Node->getDecl());
2069 switch (S.lookup(VD)) {
2070 case FixitStrategy::Kind::Array:
2071 case FixitStrategy::Kind::Span: {
2076 case FixitStrategy::Kind::Wontfix:
2077 case FixitStrategy::Kind::Iterator:
2078 return std::nullopt;
2079 case FixitStrategy::Kind::Vector:
2080 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2083 return std::nullopt;
2088static std::optional<FixItList>
2090 const auto *ArraySub = cast<ArraySubscriptExpr>(
Node->getSubExpr());
2091 const auto *DRE = cast<DeclRefExpr>(ArraySub->getBase()->IgnoreImpCasts());
2095 const Expr *Idx = ArraySub->getIdx();
2098 std::stringstream SS;
2099 bool IdxIsLitZero =
false;
2102 if ((*ICE).isZero())
2103 IdxIsLitZero =
true;
2104 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
2106 return std::nullopt;
2110 SS << (*DreString).str() <<
".data()";
2112 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
2114 return std::nullopt;
2116 SS <<
"&" << (*DreString).str() <<
".data()"
2117 <<
"[" << (*IndexString).str() <<
"]";
2123std::optional<FixItList>
2127 if (DREs.size() != 1)
2128 return std::nullopt;
2130 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
2131 if (S.lookup(VD) == FixitStrategy::Kind::Span) {
2135 StringRef varName = VD->
getName();
2139 return std::nullopt;
2144 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
2148 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
2150 if (!AddAssignLocation)
2151 return std::nullopt;
2162 return std::nullopt;
2165std::optional<FixItList>
2169 if (DREs.size() != 1)
2170 return std::nullopt;
2172 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
2173 if (S.lookup(VD) == FixitStrategy::Kind::Span) {
2175 std::stringstream SS;
2176 StringRef varName = VD->
getName();
2180 SS <<
"(" << varName.data() <<
" = " << varName.data()
2181 <<
".subspan(1)).data()";
2182 std::optional<SourceLocation> PreIncLocation =
2184 if (!PreIncLocation)
2185 return std::nullopt;
2192 return std::nullopt;
2210static std::optional<FixItList>
2212 const StringRef UserFillPlaceHolder) {
2220 if (
Init->isNullPointerConstant(
2225 NPC_ValueDependentIsNotNull)) {
2226 std::optional<SourceLocation> InitLocation =
2229 return std::nullopt;
2237 std::string ExtentText = UserFillPlaceHolder.data();
2238 StringRef One =
"1";
2243 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
2248 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
2249 if (!Ext->HasSideEffects(Ctx)) {
2250 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
2252 return std::nullopt;
2253 ExtentText = *ExtentString;
2255 }
else if (!CxxNew->isArray())
2267 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
2268 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
2269 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
2276 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
2279 return std::nullopt;
2281 StrBuffer.append(
", ");
2282 StrBuffer.append(ExtentText);
2283 StrBuffer.append(
"}");
2289#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
2290 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
2291 "failed to produce fixit for declaration '" + \
2292 (D)->getNameAsString() + "'" + (Msg))
2294#define DEBUG_NOTE_DECL_FAIL(D, Msg)
2300static std::optional<std::string>
2304 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
2309 return std::nullopt;
2311 std::string SpanTyText =
"std::span<";
2313 SpanTyText.append(*PteTyText);
2315 if (PteTyQualifiers) {
2316 SpanTyText.append(
" ");
2317 SpanTyText.append(PteTyQualifiers->getAsString());
2319 SpanTyText.append(
">");
2338 const StringRef UserFillPlaceHolder,
2352 std::stringstream SS;
2357 std::optional<FixItList> InitFixIts =
2361 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
2362 std::make_move_iterator(InitFixIts->end()));
2369 if (!EndLocForReplacement.
isValid()) {
2419static std::optional<FixItList>
2425 return std::nullopt;
2430 std::vector<std::string> NewTysTexts(NumParms);
2431 std::vector<bool> ParmsMask(NumParms,
false);
2432 bool AtLeastOneParmToFix =
false;
2434 for (
unsigned i = 0; i < NumParms; i++) {
2437 if (S.lookup(PVD) == FixitStrategy::Kind::Wontfix)
2439 if (S.lookup(PVD) != FixitStrategy::Kind::Span)
2441 return std::nullopt;
2443 std::optional<Qualifiers> PteTyQuals = std::nullopt;
2444 std::optional<std::string> PteTyText =
2449 return std::nullopt;
2453 ParmsMask[i] =
true;
2454 AtLeastOneParmToFix =
true;
2456 if (!AtLeastOneParmToFix)
2463 const auto NewOverloadSignatureCreator =
2464 [&
SM, &LangOpts, &NewTysTexts,
2465 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
2466 std::stringstream SS;
2474 SS << Prefix->str();
2476 return std::nullopt;
2480 for (
unsigned i = 0; i < NumParms; i++) {
2488 SS << NewTysTexts[i];
2491 SS <<
' ' << II->
getName().str();
2492 }
else if (
auto ParmTypeText =
2496 SS << ParmTypeText->str();
2498 return std::nullopt;
2499 if (i != NumParms - 1)
2508 const auto OldOverloadDefCreator =
2509 [&Handler, &
SM, &LangOpts, &NewTysTexts,
2510 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
2511 std::stringstream SS;
2519 << FDPrefix->str() <<
"{";
2521 return std::nullopt;
2524 SS <<
"return " << FunQualName->str() <<
"(";
2526 return std::nullopt;
2530 for (
unsigned i = 0; i < NumParms; i++) {
2539 return std::nullopt;
2546 if (i != NumParms - 1)
2557 std::optional<SourceLocation>
Loc =
getPastLoc(FReDecl,
SM, LangOpts);
2561 if (FReDecl->isThisDeclarationADefinition()) {
2562 assert(FReDecl == FD &&
"inconsistent function definition");
2565 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
2571 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
2574 FReDecl->getBeginLoc(),
" ")));
2577 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
2599 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
2615 std::stringstream SS;
2618 if (PteTyQualifiers)
2627 SS <<
' ' << PVDNameText->str();
2633 const DeclUseTracker &Tracker,
2636 const DeclStmt *DS = Tracker.lookupDecl(VD);
2639 " : variables declared this way not implemented yet");
2662 if (
auto CAT = dyn_cast<clang::ConstantArrayType>(
D->getType())) {
2663 const QualType &ArrayEltT = CAT->getElementType();
2664 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
2673 auto MaybeElemTypeTxt =
2676 if (!MaybeElemTypeTxt)
2678 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
2683 while (NextTok && !NextTok->is(tok::l_square) &&
2696 if (!MaybeArraySizeTxt)
2698 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
2699 if (ArraySizeTxt.empty()) {
2710 std::optional<StringRef> IdentText =
2719 raw_svector_ostream OS(Replacement);
2720 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
2721 << IdentText->str();
2731 const DeclUseTracker &Tracker,
2734 const DeclStmt *DS = Tracker.lookupDecl(VD);
2735 assert(DS &&
"Fixing non-local variables not implemented yet!");
2754 const DeclUseTracker &Tracker,
ASTContext &Ctx,
2756 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
2757 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
2758 if (!FD || FD !=
D) {
2769 if (FD->isMain() || FD->isConstexpr() ||
2770 FD->getTemplatedKind() != FunctionDecl::TemplatedKind::TK_NonTemplate ||
2773 isa<CXXMethodDecl>(FD) ||
2775 (FD->hasBody() && isa<CXXTryStmt>(FD->getBody())) ||
2776 FD->isOverloadedOperator()) {
2783 case FixitStrategy::Kind::Span: {
2785 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
2794 case FixitStrategy::Kind::Array: {
2802 case FixitStrategy::Kind::Iterator:
2803 case FixitStrategy::Kind::Vector:
2804 llvm_unreachable(
"FixitStrategy not implemented yet!");
2805 case FixitStrategy::Kind::Wontfix:
2806 llvm_unreachable(
"Invalid strategy!");
2808 llvm_unreachable(
"Unknown strategy!");
2816 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
2827 return isa<ParmVarDecl>(VD) &&
2835 std::map<const VarDecl *, FixItList> &FixItsForVariable,
2840 for (
const auto &[VD, Ignore] : FixItsForVariable) {
2842 if (llvm::any_of(Grp,
2843 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
2844 return !FixItsForVariable.count(GrpMember);
2849 ToErase.push_back(
Member);
2852 for (
auto *VarToErase : ToErase)
2853 FixItsForVariable.erase(VarToErase);
2864 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
2868 FixItList FixItsSharedByParms{};
2870 std::optional<FixItList> OverloadFixes =
2873 if (OverloadFixes) {
2874 FixItsSharedByParms.append(*OverloadFixes);
2880 FixItsForVariable.erase(
Member);
2882 return FixItsSharedByParms;
2886static std::map<const VarDecl *, FixItList>
2895 std::map<const VarDecl *, FixItList> FixItsForVariable;
2900 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
2901 FixItsForVariable[VD] =
2902 fixVariable(VD, S.lookup(VD),
D, Tracker, Ctx, Handler);
2905 if (FixItsForVariable[VD].empty()) {
2906 FixItsForVariable.erase(VD);
2909 for (
const auto &F : Fixables) {
2910 std::optional<FixItList> Fixits = F->getFixits(S);
2913 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
2914 Fixits->begin(), Fixits->end());
2919 VD, F->getSourceLoc(),
2920 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
2923 FixItsForVariable.erase(VD);
2942 FixItList FixItsSharedByParms{};
2944 if (
auto *FD = dyn_cast<FunctionDecl>(
D))
2946 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
2950 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
2953 for (
auto &[Var, Ignore] : FixItsForVariable) {
2954 bool AnyParm =
false;
2955 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
2957 for (
const VarDecl *GrpMate : VarGroupForVD) {
2960 if (FixItsForVariable.count(GrpMate))
2961 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
2965 assert(!FixItsSharedByParms.empty() &&
2966 "Should not try to fix a parameter that does not belong to a "
2968 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
2975 for (
auto Iter = FinalFixItsForVariable.begin();
2976 Iter != FinalFixItsForVariable.end();)
2979 Iter = FinalFixItsForVariable.erase(
Iter);
2982 return FinalFixItsForVariable;
2985template <
typename VarDeclIterTy>
2989 for (
const VarDecl *VD : UnsafeVars) {
2991 S.set(VD, FixitStrategy::Kind::Array);
2993 S.set(VD, FixitStrategy::Kind::Span);
3000 const std::vector<VarGrpTy> Groups;
3001 const std::map<const VarDecl *, unsigned> &VarGrpMap;
3002 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
3006 const std::vector<VarGrpTy> &Groups,
3007 const std::map<const VarDecl *, unsigned> &VarGrpMap,
3008 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
3009 : Groups(Groups), VarGrpMap(VarGrpMap),
3010 GrpsUnionForParms(GrpsUnionForParms) {}
3013 if (GrpsUnionForParms.contains(Var)) {
3016 return GrpsUnionForParms.getArrayRef();
3021 auto It = VarGrpMap.find(Var);
3023 if (It == VarGrpMap.end())
3024 return std::nullopt;
3025 return Groups[It->second];
3029 return GrpsUnionForParms.getArrayRef();
3035 bool EmitSuggestions) {
3044 if (
const auto *fd = dyn_cast<CXXMethodDecl>(
D)) {
3045 if (fd->getParent()->isLambda() && fd->getParent()->isLocalClass())
3051 if (
const auto *FD = dyn_cast<FunctionDecl>(
D)) {
3053 if (FReDecl->isExternC()) {
3054 EmitSuggestions =
false;
3063 auto [FixableGadgets, WarningGadgets, Tracker] =
3066 if (!EmitSuggestions) {
3070 for (
const auto &G : WarningGadgets) {
3071 G->handleUnsafeOperation(Handler,
false,
3077 assert(FixableGadgets.size() == 0 &&
3078 "Fixable gadgets found but suggestions not requested!");
3084 if (!WarningGadgets.empty()) {
3088 for (
const auto &G : FixableGadgets) {
3089 for (
const auto *DRE : G->getClaimedVarUseSites()) {
3090 Tracker.claimUse(DRE);
3106 if (WarningGadgets.empty())
3112 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
3115 for (
auto it = FixablesForAllVars.
byVar.cbegin();
3116 it != FixablesForAllVars.
byVar.cend();) {
3118 if ((!it->first->isLocalVarDecl() && !isa<ParmVarDecl>(it->first))) {
3121 (
"failed to produce fixit for '" +
3122 it->first->getNameAsString() +
3123 "' : neither local nor a parameter"));
3125 it = FixablesForAllVars.
byVar.erase(it);
3126 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
3129 (
"failed to produce fixit for '" +
3130 it->first->getNameAsString() +
3131 "' : has a reference type"));
3133 it = FixablesForAllVars.
byVar.erase(it);
3134 }
else if (Tracker.hasUnclaimedUses(it->first)) {
3135 it = FixablesForAllVars.
byVar.erase(it);
3136 }
else if (it->first->isInitCapture()) {
3139 (
"failed to produce fixit for '" +
3140 it->first->getNameAsString() +
3141 "' : init capture"));
3143 it = FixablesForAllVars.
byVar.erase(it);
3150 for (
const auto &it : UnsafeOps.
byVar) {
3151 const VarDecl *
const UnsafeVD = it.first;
3152 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
3153 if (UnclaimedDREs.empty())
3157 std::string UnclaimedUseTrace =
3162 (
"failed to produce fixit for '" + UnfixedVDName +
3163 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
3164 UnclaimedUseTrace));
3170 using DepMapTy = DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
3171 DepMapTy DependenciesMap{};
3172 DepMapTy PtrAssignmentGraph{};
3174 for (
auto it : FixablesForAllVars.
byVar) {
3175 for (
const FixableGadget *fixable : it.second) {
3176 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
3177 fixable->getStrategyImplications();
3179 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
3180 PtrAssignmentGraph[Impl.first].insert(Impl.second);
3202 std::set<const VarDecl *> VisitedVarsDirected{};
3203 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
3204 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
3206 std::queue<const VarDecl *> QueueDirected{};
3207 QueueDirected.push(Var);
3208 while (!QueueDirected.empty()) {
3209 const VarDecl *CurrentVar = QueueDirected.front();
3210 QueueDirected.pop();
3211 VisitedVarsDirected.insert(CurrentVar);
3212 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
3213 for (
const VarDecl *Adj : AdjacentNodes) {
3214 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
3215 QueueDirected.push(Adj);
3217 DependenciesMap[Var].insert(Adj);
3218 DependenciesMap[Adj].insert(Var);
3225 std::vector<VarGrpTy> Groups;
3229 std::map<const VarDecl *, unsigned> VarGrpMap;
3231 llvm::SetVector<const VarDecl *>
3236 std::set<const VarDecl *> VisitedVars{};
3237 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
3238 if (VisitedVars.find(Var) == VisitedVars.end()) {
3239 VarGrpTy &VarGroup = Groups.emplace_back();
3240 std::queue<const VarDecl *> Queue{};
3243 while (!Queue.empty()) {
3244 const VarDecl *CurrentVar = Queue.front();
3246 VisitedVars.insert(CurrentVar);
3247 VarGroup.push_back(CurrentVar);
3248 auto AdjacentNodes = DependenciesMap[CurrentVar];
3249 for (
const VarDecl *Adj : AdjacentNodes) {
3250 if (VisitedVars.find(Adj) == VisitedVars.end()) {
3256 bool HasParm =
false;
3257 unsigned GrpIdx = Groups.size() - 1;
3259 for (
const VarDecl *
V : VarGroup) {
3260 VarGrpMap[
V] = GrpIdx;
3265 GrpsUnionForParms.insert(VarGroup.begin(), VarGroup.end());
3287 for (
auto I = FixablesForAllVars.
byVar.begin();
3288 I != FixablesForAllVars.
byVar.end();) {
3290 if (!VisitedVars.count((*I).first)) {
3292 I = FixablesForAllVars.
byVar.erase(I);
3300 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
3302 return FixablesForAllVars.
byVar.count(
V);
3306 if (isa<NamedDecl>(
D))
3309 FixItsForVariableGroup =
3311 Tracker, Handler, VarGrpMgr);
3313 for (
const auto &G : UnsafeOps.
noVar) {
3314 G->handleUnsafeOperation(Handler,
false,
3318 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
3319 auto FixItsIt = FixItsForVariableGroup.find(VD);
3321 FixItsIt != FixItsForVariableGroup.end()
3322 ? std::move(FixItsIt->second)
3325 for (
const auto &G : WarningGadgets) {
3326 G->handleUnsafeOperation(Handler,
true,
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)
SourceLocation getSourceLoc() const override
virtual DeclUseList getClaimedVarUseSites() const final
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
SourceLocation getSourceLoc() 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 DeclUseList getClaimedVarUseSites() const override
SourceLocation getSourceLoc() const override
VariableGroupsManagerImpl(const std::vector< VarGrpTy > &Groups, const std::map< const VarDecl *, unsigned > &VarGrpMap, const llvm::SetVector< const VarDecl * > &GrpsUnionForParms)
VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm) const override
Returns the set of variables (including Var) that need to be fixed together in one step.
VarGrpRef getGroupOfParms() const override
Returns the non-empty group of variables that include parameters of the analyzing function,...
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.
SourceLocation getBeginLoc() const LLVM_READONLY
Attr - This represents one attribute.
A builtin binary operation expression such as "x + y" or "x <= y".
SourceLocation getBeginLoc() const LLVM_READONLY
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.
SourceLocation getBeginLoc() const LLVM_READONLY
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]).
SourceLocation getBeginLoc() const LLVM_READONLY
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.
SourceLocation getBeginLoc() const LLVM_READONLY
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
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
NestedNameSpecifier * getQualifier() const
Retrieve the nested-name-specifier that qualifies the name of this declaration, if it was present in ...
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
SourceLocation getBegin() 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.
virtual void handleUnsafeOperationInContainer(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation with a std container is found.
Represents a variable declaration or definition.
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
VarDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
bool isInlineSpecified() const
bool hasConstantInitialization() const
Determine whether this variable has constant initialization.
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.