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();
405 if (
auto *ConstArrTy =
406 Finder->getASTContext().getAsConstantArrayType(Arg0Ty)) {
407 const APSInt ConstArrSize =
APSInt(ConstArrTy->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 =
"attr_expr";
934 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
935 Op(Result.
Nodes.getNodeAs<
Expr>(OpTag)) {}
937 static bool classof(
const Gadget *G) {
938 return G->getKind() == Kind::UnsafeBufferUsageAttr;
941 static Matcher matcher() {
942 auto HasUnsafeFieldDecl =
945 auto HasUnsafeFnDecl =
953 bool IsRelatedToDecl,
959 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
965class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
966 constexpr static const char *
const OpTag =
"cxx_construct_expr";
971 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
974 static bool classof(
const Gadget *G) {
975 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
978 static Matcher matcher() {
979 auto HasUnsafeCtorDecl =
982 auto HasTwoParamSpanCtorDecl = SpanTwoParamConstructorGadget::matcher();
989 bool IsRelatedToDecl,
995 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1002class DataInvocationGadget :
public WarningGadget {
1003 constexpr static const char *
const OpTag =
"data_invocation_expr";
1008 : WarningGadget(
Kind::DataInvocation),
1011 static bool classof(
const Gadget *G) {
1012 return G->getKind() == Kind::DataInvocation;
1015 static Matcher matcher() {
1024 bool IsRelatedToDecl,
1030 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1036class ULCArraySubscriptGadget :
public FixableGadget {
1038 static constexpr const char *
const ULCArraySubscriptTag =
1039 "ArraySubscriptUnderULC";
1044 : FixableGadget(
Kind::ULCArraySubscript),
1046 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
1049 static bool classof(
const Gadget *G) {
1050 return G->getKind() == Kind::ULCArraySubscript;
1053 static Matcher matcher() {
1055 auto BaseIsArrayOrPtrDRE = hasBase(
1056 ignoringParenImpCasts(
declRefExpr(ArrayOrPtr, toSupportedVariable())));
1063 virtual std::optional<FixItList>
1067 virtual DeclUseList getClaimedVarUseSites()
const override {
1068 if (
const auto *DRE =
1069 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts())) {
1079class UPCStandalonePointerGadget :
public FixableGadget {
1081 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
1086 : FixableGadget(
Kind::UPCStandalonePointer),
1088 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
1091 static bool classof(
const Gadget *G) {
1092 return G->getKind() == Kind::UPCStandalonePointer;
1095 static Matcher matcher() {
1097 auto target =
expr(ignoringParenImpCasts(
1099 .bind(DeclRefExprTag)));
1103 virtual std::optional<FixItList>
1107 virtual DeclUseList getClaimedVarUseSites()
const override {
return {
Node}; }
1110class PointerDereferenceGadget :
public FixableGadget {
1111 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
1112 static constexpr const char *
const OperatorTag =
"op";
1119 : FixableGadget(
Kind::PointerDereference),
1124 static bool classof(
const Gadget *G) {
1125 return G->getKind() == Kind::PointerDereference;
1128 static Matcher matcher() {
1131 hasOperatorName(
"*"),
1132 has(
expr(ignoringParenImpCasts(
1133 declRefExpr(toSupportedVariable()).bind(BaseDeclRefExprTag)))))
1139 DeclUseList getClaimedVarUseSites()
const override {
1140 return {BaseDeclRefExpr};
1143 virtual std::optional<FixItList>
1151class UPCAddressofArraySubscriptGadget :
public FixableGadget {
1153 static constexpr const char *
const UPCAddressofArraySubscriptTag =
1154 "AddressofArraySubscriptUnderUPC";
1159 : FixableGadget(
Kind::ULCArraySubscript),
1161 UPCAddressofArraySubscriptTag)) {
1162 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
1165 static bool classof(
const Gadget *G) {
1166 return G->getKind() == Kind::UPCAddressofArraySubscript;
1169 static Matcher matcher() {
1172 hasOperatorName(
"&"),
1174 ignoringParenImpCasts(
declRefExpr(toSupportedVariable()))))))
1175 .bind(UPCAddressofArraySubscriptTag)))));
1178 virtual std::optional<FixItList>
1182 virtual DeclUseList getClaimedVarUseSites()
const override {
1183 const auto *ArraySubst = cast<ArraySubscriptExpr>(
Node->getSubExpr());
1185 cast<DeclRefExpr>(ArraySubst->getBase()->IgnoreParenImpCasts());
1195class DeclUseTracker {
1196 using UseSetTy = SmallSet<const DeclRefExpr *, 16>;
1197 using DefMapTy = DenseMap<const VarDecl *, const DeclStmt *>;
1200 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
1204 DeclUseTracker() =
default;
1205 DeclUseTracker(
const DeclUseTracker &) =
delete;
1206 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
1207 DeclUseTracker(DeclUseTracker &&) =
default;
1208 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
1211 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
1215 assert(Uses->count(DRE) &&
1216 "DRE not found or claimed by multiple matchers!");
1221 bool hasUnclaimedUses(
const VarDecl *VD)
const {
1223 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
1228 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
1230 for (
auto use : *Uses) {
1232 ReturnSet.insert(use);
1238 void discoverDecl(
const DeclStmt *DS) {
1240 if (
const auto *VD = dyn_cast<VarDecl>(
D)) {
1252 return Defs.lookup(VD);
1261 static constexpr const char *
const UPCPreIncrementTag =
1262 "PointerPreIncrementUnderUPC";
1267 : FixableGadget(Kind::UPCPreIncrement),
1269 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
1273 return G->getKind() == Kind::UPCPreIncrement;
1283 hasUnaryOperand(
declRefExpr(toSupportedVariable())))
1284 .bind(UPCPreIncrementTag)))));
1287 virtual std::optional<FixItList>
1292 return {dyn_cast<DeclRefExpr>(
Node->getSubExpr())};
1300 static constexpr const char *
const UUCAddAssignTag =
1301 "PointerAddAssignUnderUUC";
1302 static constexpr const char *
const OffsetTag =
"Offset";
1305 const Expr *Offset =
nullptr;
1309 : FixableGadget(Kind::UUCAddAssign),
1311 Offset(Result.
Nodes.getNodeAs<
Expr>(OffsetTag)) {
1312 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
1316 return G->getKind() == Kind::UUCAddAssign;
1326 toSupportedVariable())),
1327 hasRHS(
expr().bind(OffsetTag)))
1328 .bind(UUCAddAssignTag)))));
1332 virtual std::optional<FixItList>
1337 return {dyn_cast<DeclRefExpr>(
Node->getLHS())};
1344 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
1345 static constexpr const char *
const DerefOpTag =
"DerefOp";
1346 static constexpr const char *
const AddOpTag =
"AddOp";
1347 static constexpr const char *
const OffsetTag =
"Offset";
1356 : FixableGadget(Kind::DerefSimplePtrArithFixable),
1366 ignoringImpCasts(
declRefExpr(toSupportedVariable()).
1367 bind(BaseDeclRefExprTag)));
1368 auto PlusOverPtrAndInteger =
expr(
anyOf(
1376 hasOperatorName(
"*"),
1377 hasUnaryOperand(ignoringParens(PlusOverPtrAndInteger)))
1382 virtual std::optional<FixItList>
1389 return {BaseDeclRefExpr};
1394static std::tuple<FixableGadgetList, WarningGadgetList, DeclUseTracker>
1396 bool EmitSuggestions) {
1399 FixableGadgetList FixableGadgets;
1400 WarningGadgetList WarningGadgets;
1401 DeclUseTracker Tracker;
1409 [[maybe_unused]]
int numFound = 0;
1410#define NEXT ++numFound
1413 if (
const auto *DRE = Result.Nodes.getNodeAs<
DeclRefExpr>(
"any_dre")) {
1414 Tracker.discoverUse(DRE);
1418 if (
const auto *DS = Result.Nodes.getNodeAs<
DeclStmt>(
"any_ds")) {
1419 Tracker.discoverDecl(DS);
1426#define FIXABLE_GADGET(name) \
1427 if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
1428 FixableGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
1431#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1432#define WARNING_GADGET(name) \
1433 if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
1434 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
1437#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1439 assert(numFound >= 1 &&
"Gadgets not found in match result!");
1440 assert(numFound <= 1 &&
"Conflicting bind tags in gadgets!");
1445 GadgetFinderCallback CB;
1450 forEachDescendantEvaluatedStmt(
stmt(
anyOf(
1453 allOf(x ## Gadget::matcher().bind(#x), \
1454 notInSafeBufferOptOut(&Handler)),
1456 allOf(x ## Gadget::matcher().bind(#x), \
1457 notInSafeBufferOptOut(&Handler), \
1458 unless(ignoreUnsafeBufferInContainer(&Handler))),
1459#include
"clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1468 if (EmitSuggestions) {
1474 x ## Gadget::matcher().bind(#x),
1475#include
"clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1492 return {std::move(CB.FixableGadgets), std::move(CB.WarningGadgets),
1493 std::move(CB.Tracker)};
1499 return N1->getBeginLoc().getRawEncoding() <
1500 N2->getBeginLoc().getRawEncoding();
1505 std::map<const VarDecl *, std::set<const WarningGadget *>,
1519 for (
auto &G : AllUnsafeOperations) {
1520 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
1522 bool AssociatedWithVarDecl =
false;
1523 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
1524 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1525 result.
byVar[VD].insert(G.get());
1526 AssociatedWithVarDecl =
true;
1530 if (!AssociatedWithVarDecl) {
1531 result.
noVar.push_back(G.get());
1539 std::map<const VarDecl *, std::set<const FixableGadget *>,
1549 for (
auto &F : AllFixableOperations) {
1550 DeclUseList DREs = F->getClaimedVarUseSites();
1553 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1554 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
1558 return FixablesForUnsafeVars;
1565 std::vector<const FixItHint *> All;
1569 std::sort(All.begin(), All.end(),
1571 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
1572 H2->RemoveRange.getBegin());
1580 Hint->RemoveRange.getBegin())) {
1592std::optional<FixItList>
1593PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
1594 const auto *LeftVD = cast<VarDecl>(PtrLHS->
getDecl());
1595 const auto *RightVD = cast<VarDecl>(PtrRHS->
getDecl());
1596 switch (S.lookup(LeftVD)) {
1597 case FixitStrategy::Kind::Span:
1598 if (S.lookup(RightVD) == FixitStrategy::Kind::Span)
1600 return std::nullopt;
1601 case FixitStrategy::Kind::Wontfix:
1602 return std::nullopt;
1603 case FixitStrategy::Kind::Iterator:
1604 case FixitStrategy::Kind::Array:
1605 return std::nullopt;
1606 case FixitStrategy::Kind::Vector:
1607 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1609 return std::nullopt;
1616std::optional<FixItList>
1617CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
1618 const auto *LeftVD = cast<VarDecl>(PtrLHS->
getDecl());
1619 const auto *RightVD = cast<VarDecl>(PtrRHS->
getDecl());
1636 if (S.lookup(LeftVD) == FixitStrategy::Kind::Span) {
1637 if (S.lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
1640 }
else if (S.lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
1641 if (S.lookup(RightVD) == FixitStrategy::Kind::Array) {
1645 return std::nullopt;
1648std::optional<FixItList>
1650 const auto *LeftVD = PtrInitLHS;
1651 const auto *RightVD = cast<VarDecl>(PtrInitRHS->
getDecl());
1652 switch (S.lookup(LeftVD)) {
1653 case FixitStrategy::Kind::Span:
1654 if (S.lookup(RightVD) == FixitStrategy::Kind::Span)
1656 return std::nullopt;
1657 case FixitStrategy::Kind::Wontfix:
1658 return std::nullopt;
1659 case FixitStrategy::Kind::Iterator:
1660 case FixitStrategy::Kind::Array:
1661 return std::nullopt;
1662 case FixitStrategy::Kind::Vector:
1663 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1665 return std::nullopt;
1671 if (ConstVal->isNegative())
1678std::optional<FixItList>
1679ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
1680 if (
const auto *DRE =
1681 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts()))
1682 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1683 switch (S.lookup(VD)) {
1684 case FixitStrategy::Kind::Span: {
1691 return std::nullopt;
1695 case FixitStrategy::Kind::Array:
1697 case FixitStrategy::Kind::Wontfix:
1698 case FixitStrategy::Kind::Iterator:
1699 case FixitStrategy::Kind::Vector:
1700 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1703 return std::nullopt;
1706static std::optional<FixItList>
1709std::optional<FixItList>
1710UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
1711 auto DREs = getClaimedVarUseSites();
1712 const auto *VD = cast<VarDecl>(DREs.front()->getDecl());
1714 switch (S.lookup(VD)) {
1715 case FixitStrategy::Kind::Span:
1717 case FixitStrategy::Kind::Wontfix:
1718 case FixitStrategy::Kind::Iterator:
1719 case FixitStrategy::Kind::Array:
1720 return std::nullopt;
1721 case FixitStrategy::Kind::Vector:
1722 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1724 return std::nullopt;
1729 static const char *
const EOL =
"\n";
1735 std::string
s = std::string(
"<# ");
1736 s += HintTextToUser;
1742template <
typename NodeTy>
1743static std::optional<SourceLocation>
1752 return std::nullopt;
1756template <
typename NodeTy>
1764 return std::nullopt;
1771 std::optional<SourceLocation> LastCharLoc =
getPastLoc(
E,
SM, LangOpts);
1778 return std::nullopt;
1791 return std::nullopt;
1803static std::optional<StringRef>
1812 return std::nullopt;
1813 return getRangeText({ParmIdentBeginLoc, ParmIdentEndLoc},
SM, LangOpts);
1826 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
1827 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
1828 VD->getBeginLoc())) &&
1829 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
1830 At->getRange().getBegin()));
1834 AttrRangeOverlapping;
1858static std::optional<std::string>
1861 std::optional<Qualifiers> *QualifiersToAppend) {
1866 "Expecting a VarDecl of type of pointer to object type");
1875 case TypeLoc::ConstantArray:
1876 case TypeLoc::IncompleteArray:
1877 case TypeLoc::VariableArray:
1878 case TypeLoc::DependentSizedArray:
1879 case TypeLoc::Decayed:
1880 assert(isa<ParmVarDecl>(VD) &&
"An array type shall not be treated as a "
1881 "pointer type unless it decays.");
1884 case TypeLoc::Pointer:
1888 return std::nullopt;
1893 return std::nullopt;
1901 return std::nullopt;
1908 if (!PteEndOfTokenLoc.
isValid())
1911 return std::nullopt;
1912 if (!
SM.isBeforeInTranslationUnit(PteEndOfTokenLoc, IdentLoc)) {
1919 return std::nullopt;
1954 std::optional<Qualifiers> Quals = std::nullopt) {
1955 const char *
const SpanOpen =
"std::span<";
1958 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
1959 return SpanOpen + EltTyText.str() +
'>';
1962std::optional<FixItList>
1964 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->
getDecl());
1966 if (VD &&
s.lookup(VD) == FixitStrategy::Kind::Span) {
1970 if (ConstVal->isNegative())
1971 return std::nullopt;
1999 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
2001 return std::nullopt;
2006 std::optional<SourceLocation> AddOpLocation =
2008 std::optional<SourceLocation> DerefOpLocation =
2011 if (!AddOpLocation || !DerefOpLocation)
2012 return std::nullopt;
2022 return std::nullopt;
2025std::optional<FixItList>
2026PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
2028 switch (S.lookup(VD)) {
2029 case FixitStrategy::Kind::Span: {
2037 if (
auto LocPastOperand =
2044 case FixitStrategy::Kind::Iterator:
2045 case FixitStrategy::Kind::Array:
2046 return std::nullopt;
2047 case FixitStrategy::Kind::Vector:
2048 llvm_unreachable(
"FixitStrategy not implemented yet!");
2049 case FixitStrategy::Kind::Wontfix:
2050 llvm_unreachable(
"Invalid strategy!");
2053 return std::nullopt;
2060 std::optional<SourceLocation> EndOfOperand =
2066 return std::nullopt;
2071std::optional<FixItList>
2072UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
2073 const auto VD = cast<VarDecl>(
Node->getDecl());
2074 switch (S.lookup(VD)) {
2075 case FixitStrategy::Kind::Array:
2076 case FixitStrategy::Kind::Span: {
2081 case FixitStrategy::Kind::Wontfix:
2082 case FixitStrategy::Kind::Iterator:
2083 return std::nullopt;
2084 case FixitStrategy::Kind::Vector:
2085 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2088 return std::nullopt;
2093static std::optional<FixItList>
2095 const auto *ArraySub = cast<ArraySubscriptExpr>(
Node->getSubExpr());
2096 const auto *DRE = cast<DeclRefExpr>(ArraySub->getBase()->IgnoreImpCasts());
2100 const Expr *Idx = ArraySub->getIdx();
2103 std::stringstream SS;
2104 bool IdxIsLitZero =
false;
2107 if ((*ICE).isZero())
2108 IdxIsLitZero =
true;
2109 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
2111 return std::nullopt;
2115 SS << (*DreString).str() <<
".data()";
2117 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
2119 return std::nullopt;
2121 SS <<
"&" << (*DreString).str() <<
".data()"
2122 <<
"[" << (*IndexString).str() <<
"]";
2128std::optional<FixItList>
2132 if (DREs.size() != 1)
2133 return std::nullopt;
2135 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
2136 if (S.lookup(VD) == FixitStrategy::Kind::Span) {
2140 StringRef varName = VD->
getName();
2144 return std::nullopt;
2149 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
2153 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
2155 if (!AddAssignLocation)
2156 return std::nullopt;
2167 return std::nullopt;
2170std::optional<FixItList>
2174 if (DREs.size() != 1)
2175 return std::nullopt;
2177 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
2178 if (S.lookup(VD) == FixitStrategy::Kind::Span) {
2180 std::stringstream SS;
2181 StringRef varName = VD->
getName();
2185 SS <<
"(" << varName.data() <<
" = " << varName.data()
2186 <<
".subspan(1)).data()";
2187 std::optional<SourceLocation> PreIncLocation =
2189 if (!PreIncLocation)
2190 return std::nullopt;
2197 return std::nullopt;
2215static std::optional<FixItList>
2217 const StringRef UserFillPlaceHolder) {
2225 if (
Init->isNullPointerConstant(
2230 NPC_ValueDependentIsNotNull)) {
2231 std::optional<SourceLocation> InitLocation =
2234 return std::nullopt;
2242 std::string ExtentText = UserFillPlaceHolder.data();
2243 StringRef One =
"1";
2248 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
2253 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
2254 if (!Ext->HasSideEffects(Ctx)) {
2255 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
2257 return std::nullopt;
2258 ExtentText = *ExtentString;
2260 }
else if (!CxxNew->isArray())
2272 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
2273 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
2274 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
2281 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
2284 return std::nullopt;
2286 StrBuffer.append(
", ");
2287 StrBuffer.append(ExtentText);
2288 StrBuffer.append(
"}");
2294#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
2295 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
2296 "failed to produce fixit for declaration '" + \
2297 (D)->getNameAsString() + "'" + (Msg))
2299#define DEBUG_NOTE_DECL_FAIL(D, Msg)
2305static std::optional<std::string>
2309 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
2314 return std::nullopt;
2316 std::string SpanTyText =
"std::span<";
2318 SpanTyText.append(*PteTyText);
2320 if (PteTyQualifiers) {
2321 SpanTyText.append(
" ");
2322 SpanTyText.append(PteTyQualifiers->getAsString());
2324 SpanTyText.append(
">");
2343 const StringRef UserFillPlaceHolder,
2357 std::stringstream SS;
2362 std::optional<FixItList> InitFixIts =
2366 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
2367 std::make_move_iterator(InitFixIts->end()));
2374 if (!EndLocForReplacement.
isValid()) {
2424static std::optional<FixItList>
2430 return std::nullopt;
2435 std::vector<std::string> NewTysTexts(NumParms);
2436 std::vector<bool> ParmsMask(NumParms,
false);
2437 bool AtLeastOneParmToFix =
false;
2439 for (
unsigned i = 0; i < NumParms; i++) {
2442 if (S.lookup(PVD) == FixitStrategy::Kind::Wontfix)
2444 if (S.lookup(PVD) != FixitStrategy::Kind::Span)
2446 return std::nullopt;
2448 std::optional<Qualifiers> PteTyQuals = std::nullopt;
2449 std::optional<std::string> PteTyText =
2454 return std::nullopt;
2458 ParmsMask[i] =
true;
2459 AtLeastOneParmToFix =
true;
2461 if (!AtLeastOneParmToFix)
2468 const auto NewOverloadSignatureCreator =
2469 [&
SM, &LangOpts, &NewTysTexts,
2470 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
2471 std::stringstream SS;
2479 SS << Prefix->str();
2481 return std::nullopt;
2485 for (
unsigned i = 0; i < NumParms; i++) {
2493 SS << NewTysTexts[i];
2496 SS <<
' ' << II->
getName().str();
2497 }
else if (
auto ParmTypeText =
2501 SS << ParmTypeText->str();
2503 return std::nullopt;
2504 if (i != NumParms - 1)
2513 const auto OldOverloadDefCreator =
2514 [&Handler, &
SM, &LangOpts, &NewTysTexts,
2515 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
2516 std::stringstream SS;
2524 << FDPrefix->str() <<
"{";
2526 return std::nullopt;
2529 SS <<
"return " << FunQualName->str() <<
"(";
2531 return std::nullopt;
2535 for (
unsigned i = 0; i < NumParms; i++) {
2544 return std::nullopt;
2551 if (i != NumParms - 1)
2562 std::optional<SourceLocation>
Loc =
getPastLoc(FReDecl,
SM, LangOpts);
2566 if (FReDecl->isThisDeclarationADefinition()) {
2567 assert(FReDecl == FD &&
"inconsistent function definition");
2570 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
2576 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
2579 FReDecl->getBeginLoc(),
" ")));
2582 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
2604 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
2620 std::stringstream SS;
2623 if (PteTyQualifiers)
2632 SS <<
' ' << PVDNameText->str();
2638 const DeclUseTracker &Tracker,
2641 const DeclStmt *DS = Tracker.lookupDecl(VD);
2644 " : variables declared this way not implemented yet");
2668 const QualType &ArrayEltT = CAT->getElementType();
2669 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
2678 auto MaybeElemTypeTxt =
2681 if (!MaybeElemTypeTxt)
2683 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
2688 while (NextTok && !NextTok->is(tok::l_square) &&
2701 if (!MaybeArraySizeTxt)
2703 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
2704 if (ArraySizeTxt.empty()) {
2715 std::optional<StringRef> IdentText =
2724 raw_svector_ostream OS(Replacement);
2725 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
2726 << IdentText->str();
2736 const DeclUseTracker &Tracker,
2739 const DeclStmt *DS = Tracker.lookupDecl(VD);
2740 assert(DS &&
"Fixing non-local variables not implemented yet!");
2759 const DeclUseTracker &Tracker,
ASTContext &Ctx,
2761 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
2762 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
2763 if (!FD || FD !=
D) {
2774 if (FD->isMain() || FD->isConstexpr() ||
2775 FD->getTemplatedKind() != FunctionDecl::TemplatedKind::TK_NonTemplate ||
2778 isa<CXXMethodDecl>(FD) ||
2780 (FD->hasBody() && isa<CXXTryStmt>(FD->getBody())) ||
2781 FD->isOverloadedOperator()) {
2788 case FixitStrategy::Kind::Span: {
2790 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
2799 case FixitStrategy::Kind::Array: {
2806 case FixitStrategy::Kind::Iterator:
2807 case FixitStrategy::Kind::Vector:
2808 llvm_unreachable(
"FixitStrategy not implemented yet!");
2809 case FixitStrategy::Kind::Wontfix:
2810 llvm_unreachable(
"Invalid strategy!");
2812 llvm_unreachable(
"Unknown strategy!");
2820 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
2831 return isa<ParmVarDecl>(VD) &&
2839 std::map<const VarDecl *, FixItList> &FixItsForVariable,
2844 for (
const auto &[VD, Ignore] : FixItsForVariable) {
2846 if (llvm::any_of(Grp,
2847 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
2848 return !FixItsForVariable.count(GrpMember);
2853 ToErase.push_back(
Member);
2856 for (
auto *VarToErase : ToErase)
2857 FixItsForVariable.erase(VarToErase);
2868 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
2872 FixItList FixItsSharedByParms{};
2874 std::optional<FixItList> OverloadFixes =
2877 if (OverloadFixes) {
2878 FixItsSharedByParms.append(*OverloadFixes);
2884 FixItsForVariable.erase(
Member);
2886 return FixItsSharedByParms;
2890static std::map<const VarDecl *, FixItList>
2899 std::map<const VarDecl *, FixItList> FixItsForVariable;
2904 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
2905 FixItsForVariable[VD] =
2906 fixVariable(VD, S.lookup(VD),
D, Tracker, Ctx, Handler);
2909 if (FixItsForVariable[VD].empty()) {
2910 FixItsForVariable.erase(VD);
2913 for (
const auto &F : Fixables) {
2914 std::optional<FixItList> Fixits = F->getFixits(S);
2917 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
2918 Fixits->begin(), Fixits->end());
2923 VD, F->getSourceLoc(),
2924 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
2927 FixItsForVariable.erase(VD);
2946 FixItList FixItsSharedByParms{};
2948 if (
auto *FD = dyn_cast<FunctionDecl>(
D))
2950 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
2954 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
2957 for (
auto &[Var, Ignore] : FixItsForVariable) {
2958 bool AnyParm =
false;
2959 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
2961 for (
const VarDecl *GrpMate : VarGroupForVD) {
2964 if (FixItsForVariable.count(GrpMate))
2965 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
2969 assert(!FixItsSharedByParms.empty() &&
2970 "Should not try to fix a parameter that does not belong to a "
2972 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
2979 for (
auto Iter = FinalFixItsForVariable.begin();
2980 Iter != FinalFixItsForVariable.end();)
2983 Iter = FinalFixItsForVariable.erase(
Iter);
2986 return FinalFixItsForVariable;
2989template <
typename VarDeclIterTy>
2993 for (
const VarDecl *VD : UnsafeVars) {
2995 S.set(VD, FixitStrategy::Kind::Array);
2997 S.set(VD, FixitStrategy::Kind::Span);
3004 const std::vector<VarGrpTy> Groups;
3005 const std::map<const VarDecl *, unsigned> &VarGrpMap;
3006 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
3010 const std::vector<VarGrpTy> &Groups,
3011 const std::map<const VarDecl *, unsigned> &VarGrpMap,
3012 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
3013 : Groups(Groups), VarGrpMap(VarGrpMap),
3014 GrpsUnionForParms(GrpsUnionForParms) {}
3017 if (GrpsUnionForParms.contains(Var)) {
3020 return GrpsUnionForParms.getArrayRef();
3025 auto It = VarGrpMap.find(Var);
3027 if (It == VarGrpMap.end())
3028 return std::nullopt;
3029 return Groups[It->second];
3033 return GrpsUnionForParms.getArrayRef();
3039 bool EmitSuggestions) {
3048 if (
const auto *fd = dyn_cast<CXXMethodDecl>(
D)) {
3049 if (fd->getParent()->isLambda() && fd->getParent()->isLocalClass())
3055 if (
const auto *FD = dyn_cast<FunctionDecl>(
D)) {
3057 if (FReDecl->isExternC()) {
3058 EmitSuggestions =
false;
3067 auto [FixableGadgets, WarningGadgets, Tracker] =
3070 if (!EmitSuggestions) {
3074 for (
const auto &G : WarningGadgets) {
3075 G->handleUnsafeOperation(Handler,
false,
3081 assert(FixableGadgets.size() == 0 &&
3082 "Fixable gadgets found but suggestions not requested!");
3088 if (!WarningGadgets.empty()) {
3092 for (
const auto &G : FixableGadgets) {
3093 for (
const auto *DRE : G->getClaimedVarUseSites()) {
3094 Tracker.claimUse(DRE);
3110 if (WarningGadgets.empty())
3116 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
3119 for (
auto it = FixablesForAllVars.
byVar.cbegin();
3120 it != FixablesForAllVars.
byVar.cend();) {
3122 if ((!it->first->isLocalVarDecl() && !isa<ParmVarDecl>(it->first))) {
3125 (
"failed to produce fixit for '" +
3126 it->first->getNameAsString() +
3127 "' : neither local nor a parameter"));
3129 it = FixablesForAllVars.
byVar.erase(it);
3130 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
3133 (
"failed to produce fixit for '" +
3134 it->first->getNameAsString() +
3135 "' : has a reference type"));
3137 it = FixablesForAllVars.
byVar.erase(it);
3138 }
else if (Tracker.hasUnclaimedUses(it->first)) {
3139 it = FixablesForAllVars.
byVar.erase(it);
3140 }
else if (it->first->isInitCapture()) {
3143 (
"failed to produce fixit for '" +
3144 it->first->getNameAsString() +
3145 "' : init capture"));
3147 it = FixablesForAllVars.
byVar.erase(it);
3154 for (
const auto &it : UnsafeOps.
byVar) {
3155 const VarDecl *
const UnsafeVD = it.first;
3156 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
3157 if (UnclaimedDREs.empty())
3161 std::string UnclaimedUseTrace =
3166 (
"failed to produce fixit for '" + UnfixedVDName +
3167 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
3168 UnclaimedUseTrace));
3174 using DepMapTy = DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
3175 DepMapTy DependenciesMap{};
3176 DepMapTy PtrAssignmentGraph{};
3178 for (
auto it : FixablesForAllVars.
byVar) {
3179 for (
const FixableGadget *fixable : it.second) {
3180 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
3181 fixable->getStrategyImplications();
3183 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
3184 PtrAssignmentGraph[Impl.first].insert(Impl.second);
3206 std::set<const VarDecl *> VisitedVarsDirected{};
3207 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
3208 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
3210 std::queue<const VarDecl *> QueueDirected{};
3211 QueueDirected.push(Var);
3212 while (!QueueDirected.empty()) {
3213 const VarDecl *CurrentVar = QueueDirected.front();
3214 QueueDirected.pop();
3215 VisitedVarsDirected.insert(CurrentVar);
3216 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
3217 for (
const VarDecl *Adj : AdjacentNodes) {
3218 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
3219 QueueDirected.push(Adj);
3221 DependenciesMap[Var].insert(Adj);
3222 DependenciesMap[Adj].insert(Var);
3229 std::vector<VarGrpTy> Groups;
3233 std::map<const VarDecl *, unsigned> VarGrpMap;
3235 llvm::SetVector<const VarDecl *>
3240 std::set<const VarDecl *> VisitedVars{};
3241 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
3242 if (VisitedVars.find(Var) == VisitedVars.end()) {
3243 VarGrpTy &VarGroup = Groups.emplace_back();
3244 std::queue<const VarDecl *> Queue{};
3247 while (!Queue.empty()) {
3248 const VarDecl *CurrentVar = Queue.front();
3250 VisitedVars.insert(CurrentVar);
3251 VarGroup.push_back(CurrentVar);
3252 auto AdjacentNodes = DependenciesMap[CurrentVar];
3253 for (
const VarDecl *Adj : AdjacentNodes) {
3254 if (VisitedVars.find(Adj) == VisitedVars.end()) {
3260 bool HasParm =
false;
3261 unsigned GrpIdx = Groups.size() - 1;
3263 for (
const VarDecl *
V : VarGroup) {
3264 VarGrpMap[
V] = GrpIdx;
3269 GrpsUnionForParms.insert(VarGroup.begin(), VarGroup.end());
3291 for (
auto I = FixablesForAllVars.
byVar.begin();
3292 I != FixablesForAllVars.
byVar.end();) {
3294 if (!VisitedVars.count((*I).first)) {
3296 I = FixablesForAllVars.
byVar.erase(I);
3304 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
3306 return FixablesForAllVars.
byVar.count(
V);
3310 if (isa<NamedDecl>(
D))
3313 FixItsForVariableGroup =
3315 Tracker, Handler, VarGrpMgr);
3317 for (
const auto &G : UnsafeOps.
noVar) {
3318 G->handleUnsafeOperation(Handler,
false,
3322 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
3323 auto FixItsIt = FixItsForVariableGroup.find(VD);
3325 FixItsIt != FixItsForVariableGroup.end()
3326 ? std::move(FixItsIt->second)
3329 for (
const auto &G : WarningGadgets) {
3330 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...
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 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).
const internal::VariadicDynCastAllOfMatcher< Decl, FieldDecl > fieldDecl
Matches field declarations.
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.
const internal::VariadicDynCastAllOfMatcher< Stmt, MemberExpr > memberExpr
Matches member expressions.
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.