17#include "llvm/ADT/SmallVector.h"
25using namespace ast_matchers;
32 std::string VisitStmt(
const Stmt *S) {
return S->getStmtClassName(); }
35 return "BinaryOperator(" + BO->
getOpcodeStr().str() +
")";
49static std::string getDREAncestorString(
const DeclRefExpr *DRE,
53 StmtDebugPrinter StmtPriner;
56 SS << StmtPriner.Visit(St);
60 if (StParents.
size() > 1)
61 return "unavailable due to multiple parents";
62 if (StParents.
size() == 0)
85 internal::ASTMatchFinder *Finder,
86 internal::BoundNodesTreeBuilder *Builder,
87 internal::ASTMatchFinder::BindKind Bind,
88 const bool ignoreUnevaluatedContext)
89 : Matcher(Matcher), Finder(Finder), Builder(Builder), Bind(Bind),
90 Matches(
false), ignoreUnevaluatedContext(ignoreUnevaluatedContext) {}
98 *Builder = ResultBindings;
117 if (isa<FunctionDecl, BlockDecl, ObjCMethodDecl>(
Node))
125 if(ignoreUnevaluatedContext)
127 return VisitorBase::TraverseGenericSelectionExpr(
Node);
132 if(ignoreUnevaluatedContext)
134 return VisitorBase::TraverseUnaryExprOrTypeTraitExpr(
Node);
139 if(ignoreUnevaluatedContext)
141 return VisitorBase::TraverseTypeOfExprTypeLoc(
Node);
146 if(ignoreUnevaluatedContext)
148 return VisitorBase::TraverseDecltypeTypeLoc(
Node);
153 if(ignoreUnevaluatedContext)
155 return VisitorBase::TraverseCXXNoexceptExpr(
Node);
160 if(ignoreUnevaluatedContext)
162 return VisitorBase::TraverseCXXTypeidExpr(
Node);
184 template <
typename T>
bool match(
const T &
Node) {
185 internal::BoundNodesTreeBuilder RecursiveBuilder(*Builder);
188 &RecursiveBuilder)) {
189 ResultBindings.addMatch(RecursiveBuilder);
191 if (Bind != internal::ASTMatchFinder::BK_All)
197 const internal::DynTypedMatcher *
const Matcher;
198 internal::ASTMatchFinder *
const Finder;
199 internal::BoundNodesTreeBuilder *
const Builder;
200 internal::BoundNodesTreeBuilder ResultBindings;
201 const internal::ASTMatchFinder::BindKind Bind;
203 bool ignoreUnevaluatedContext;
212 return hasType(hasCanonicalType(
arrayType()));
216 const DynTypedMatcher &DTM =
static_cast<DynTypedMatcher
>(innerMatcher);
223 const DynTypedMatcher &DTM =
static_cast<DynTypedMatcher
>(innerMatcher);
232 return !Handler->isSafeBufferOptOut(
Node.getBeginLoc());
236 return innerMatcher.matches(*
Node.getSubExpr(), Finder, Builder);
241 return Node.getOpcode() == UnaryOperator::Opcode::UO_PreInc;
251 hasCastKind(CastKind::CK_LValueToRValue),
252 castSubExpr(innerMatcher)),
264static internal::Matcher<Stmt>
274 auto CallArgMatcher =
275 callExpr(forEachArgumentWithParam(InnerMatcher,
279 auto CastOperandMatcher =
281 hasCastKind(CastKind::CK_PointerToBoolean)),
284 auto CompOperandMatcher =
290 auto PtrSubtractionMatcher =
297 eachOf(hasLHS(InnerMatcher),
298 hasRHS(InnerMatcher)));
300 return stmt(
anyOf(CallArgMatcher, CastOperandMatcher, CompOperandMatcher,
301 PtrSubtractionMatcher));
316static internal::Matcher<Stmt>
323 auto IfStmtThen =
ifStmt(hasThen(InnerMatcher));
324 auto IfStmtElse =
ifStmt(hasElse(InnerMatcher));
326 return stmt(
anyOf(CompStmt, IfStmtThen, IfStmtElse));
355#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
361 using Matcher =
decltype(
stmt());
363 Gadget(Kind K) : K(K) {}
368 StringRef getDebugName()
const {
370#define GADGET(x) case Kind::x: return #x;
371#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
373 llvm_unreachable(
"Unhandled Gadget::Kind enum");
377 virtual bool isWarningGadget()
const = 0;
378 virtual const Stmt *getBaseStmt()
const = 0;
383 virtual DeclUseList getClaimedVarUseSites()
const = 0;
385 virtual ~Gadget() =
default;
394class WarningGadget :
public Gadget {
396 WarningGadget(Kind K) : Gadget(K) {}
398 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
399 bool isWarningGadget() const final {
return true; }
406class FixableGadget :
public Gadget {
408 FixableGadget(Kind K) : Gadget(K) {}
410 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
411 bool isWarningGadget() const final {
return false; }
416 virtual std::optional<FixItList> getFixits(
const Strategy &)
const {
425 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
426 getStrategyImplications()
const {
431static auto toSupportedVariable() {
435using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
436using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
440class IncrementGadget :
public WarningGadget {
441 static constexpr const char *
const OpTag =
"op";
446 : WarningGadget(
Kind::Increment),
449 static bool classof(
const Gadget *G) {
450 return G->getKind() == Kind::Increment;
453 static Matcher matcher() {
455 hasOperatorName(
"++"),
460 const UnaryOperator *getBaseStmt()
const override {
return Op; }
462 DeclUseList getClaimedVarUseSites()
const override {
464 if (
const auto *DRE =
469 return std::move(Uses);
475class DecrementGadget :
public WarningGadget {
476 static constexpr const char *
const OpTag =
"op";
481 : WarningGadget(
Kind::Decrement),
484 static bool classof(
const Gadget *G) {
485 return G->getKind() == Kind::Decrement;
488 static Matcher matcher() {
490 hasOperatorName(
"--"),
495 const UnaryOperator *getBaseStmt()
const override {
return Op; }
497 DeclUseList getClaimedVarUseSites()
const override {
498 if (
const auto *DRE =
509class ArraySubscriptGadget :
public WarningGadget {
510 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
515 : WarningGadget(
Kind::ArraySubscript),
518 static bool classof(
const Gadget *G) {
519 return G->getKind() == Kind::ArraySubscript;
522 static Matcher matcher() {
527 hasBase(ignoringParenImpCasts(
532 .bind(ArraySubscrTag));
538 DeclUseList getClaimedVarUseSites()
const override {
539 if (
const auto *DRE =
552class PointerArithmeticGadget :
public WarningGadget {
553 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
554 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
560 : WarningGadget(
Kind::PointerArithmetic),
562 Ptr(Result.
Nodes.getNodeAs<
Expr>(PointerArithmeticPointerTag)) {}
564 static bool classof(
const Gadget *G) {
565 return G->getKind() == Kind::PointerArithmetic;
568 static Matcher matcher() {
569 auto HasIntegerType =
anyOf(hasType(isInteger()), hasType(
enumType()));
571 allOf(hasOperatorName(
"+"),
573 hasLHS(HasIntegerType));
575 allOf(
anyOf(hasOperatorName(
"+"), hasOperatorName(
"-"),
576 hasOperatorName(
"+="), hasOperatorName(
"-=")),
578 hasRHS(HasIntegerType));
581 .bind(PointerArithmeticTag));
584 const Stmt *getBaseStmt()
const override {
return PA; }
586 DeclUseList getClaimedVarUseSites()
const override {
601class PointerInitGadget :
public FixableGadget {
603 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
604 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
610 : FixableGadget(
Kind::PointerInit),
611 PtrInitLHS(Result.
Nodes.getNodeAs<
VarDecl>(PointerInitLHSTag)),
614 static bool classof(
const Gadget *G) {
615 return G->getKind() == Kind::PointerInit;
618 static Matcher matcher() {
622 toSupportedVariable()).
623 bind(PointerInitRHSTag)))).
624 bind(PointerInitLHSTag)));
626 return stmt(PtrInitStmt);
629 virtual std::optional<FixItList> getFixits(
const Strategy &S)
const override;
631 virtual const Stmt *getBaseStmt()
const override {
637 virtual DeclUseList getClaimedVarUseSites()
const override {
638 return DeclUseList{PtrInitRHS};
641 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
642 getStrategyImplications()
const override {
643 return std::make_pair(PtrInitLHS,
644 cast<VarDecl>(PtrInitRHS->
getDecl()));
652class PointerAssignmentGadget :
public FixableGadget {
654 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
655 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
661 : FixableGadget(
Kind::PointerAssignment),
665 static bool classof(
const Gadget *G) {
666 return G->getKind() == Kind::PointerAssignment;
669 static Matcher matcher() {
672 toSupportedVariable()).
673 bind(PointerAssignRHSTag))),
675 toSupportedVariable()).
676 bind(PointerAssignLHSTag))));
681 virtual std::optional<FixItList> getFixits(
const Strategy &S)
const override;
683 virtual const Stmt *getBaseStmt()
const override {
689 virtual DeclUseList getClaimedVarUseSites()
const override {
690 return DeclUseList{PtrLHS, PtrRHS};
693 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
694 getStrategyImplications()
const override {
695 return std::make_pair(cast<VarDecl>(PtrLHS->
getDecl()),
696 cast<VarDecl>(PtrRHS->
getDecl()));
702class UnsafeBufferUsageAttrGadget :
public WarningGadget {
703 constexpr static const char *
const OpTag =
"call_expr";
708 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
711 static bool classof(
const Gadget *G) {
712 return G->getKind() == Kind::UnsafeBufferUsageAttr;
715 static Matcher matcher() {
719 const Stmt *getBaseStmt()
const override {
return Op; }
721 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
727class ULCArraySubscriptGadget :
public FixableGadget {
729 static constexpr const char *
const ULCArraySubscriptTag =
730 "ArraySubscriptUnderULC";
735 : FixableGadget(
Kind::ULCArraySubscript),
737 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
740 static bool classof(
const Gadget *G) {
741 return G->getKind() == Kind::ULCArraySubscript;
744 static Matcher matcher() {
746 auto BaseIsArrayOrPtrDRE =
747 hasBase(ignoringParenImpCasts(
declRefExpr(ArrayOrPtr,
748 toSupportedVariable())));
755 virtual std::optional<FixItList> getFixits(
const Strategy &S)
const override;
757 virtual const Stmt *getBaseStmt()
const override {
return Node; }
759 virtual DeclUseList getClaimedVarUseSites()
const override {
760 if (
const auto *DRE =
761 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts())) {
771class UPCStandalonePointerGadget :
public FixableGadget {
773 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
778 : FixableGadget(
Kind::UPCStandalonePointer),
780 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
783 static bool classof(
const Gadget *G) {
784 return G->getKind() == Kind::UPCStandalonePointer;
787 static Matcher matcher() {
791 toSupportedVariable())).bind(DeclRefExprTag)));
795 virtual std::optional<FixItList> getFixits(
const Strategy &S)
const override;
797 virtual const Stmt *getBaseStmt()
const override {
return Node; }
799 virtual DeclUseList getClaimedVarUseSites()
const override {
804class PointerDereferenceGadget :
public FixableGadget {
805 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
806 static constexpr const char *
const OperatorTag =
"op";
813 : FixableGadget(
Kind::PointerDereference),
818 static bool classof(
const Gadget *G) {
819 return G->getKind() == Kind::PointerDereference;
822 static Matcher matcher() {
825 hasOperatorName(
"*"),
826 has(
expr(ignoringParenImpCasts(
827 declRefExpr(toSupportedVariable()).bind(BaseDeclRefExprTag)))))
833 DeclUseList getClaimedVarUseSites()
const override {
834 return {BaseDeclRefExpr};
837 virtual const Stmt *getBaseStmt() const final {
return Op; }
839 virtual std::optional<FixItList> getFixits(
const Strategy &S)
const override;
845class UPCAddressofArraySubscriptGadget :
public FixableGadget {
847 static constexpr const char *
const UPCAddressofArraySubscriptTag =
848 "AddressofArraySubscriptUnderUPC";
853 : FixableGadget(
Kind::ULCArraySubscript),
855 UPCAddressofArraySubscriptTag)) {
856 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
859 static bool classof(
const Gadget *G) {
860 return G->getKind() == Kind::UPCAddressofArraySubscript;
863 static Matcher matcher() {
868 toSupportedVariable()))))))
869 .bind(UPCAddressofArraySubscriptTag)))));
872 virtual std::optional<FixItList> getFixits(
const Strategy &)
const override;
874 virtual const Stmt *getBaseStmt()
const override {
return Node; }
876 virtual DeclUseList getClaimedVarUseSites()
const override {
877 const auto *ArraySubst = cast<ArraySubscriptExpr>(
Node->getSubExpr());
879 cast<DeclRefExpr>(ArraySubst->getBase()->IgnoreImpCasts());
889class DeclUseTracker {
890 using UseSetTy = SmallSet<const DeclRefExpr *, 16>;
891 using DefMapTy = DenseMap<const VarDecl *, const DeclStmt *>;
894 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
898 DeclUseTracker() =
default;
899 DeclUseTracker(
const DeclUseTracker &) =
delete;
900 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
901 DeclUseTracker(DeclUseTracker &&) =
default;
902 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
905 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
909 assert(Uses->count(DRE) &&
910 "DRE not found or claimed by multiple matchers!");
915 bool hasUnclaimedUses(
const VarDecl *VD)
const {
917 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
922 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
924 for (
auto use : *Uses) {
926 ReturnSet.insert(use);
932 void discoverDecl(
const DeclStmt *DS) {
934 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
946 return Defs.lookup(VD);
967 using MapTy = llvm::DenseMap<const VarDecl *, Kind>;
972 Strategy() =
default;
973 Strategy(
const Strategy &) =
delete;
974 Strategy &operator=(
const Strategy &) =
delete;
975 Strategy(Strategy &&) =
default;
976 Strategy &operator=(Strategy &&) =
default;
978 void set(
const VarDecl *VD, Kind K) { Map[VD] = K; }
981 auto I = Map.find(VD);
983 return Kind::Wontfix;
995 static constexpr const char *
const UPCPreIncrementTag =
996 "PointerPreIncrementUnderUPC";
1001 : FixableGadget(Kind::UPCPreIncrement),
1003 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
1007 return G->getKind() == Kind::UPCPreIncrement;
1018 toSupportedVariable()))
1019 ).bind(UPCPreIncrementTag)))));
1022 virtual std::optional<FixItList>
getFixits(
const Strategy &S)
const override;
1027 return {dyn_cast<DeclRefExpr>(
Node->getSubExpr())};
1034 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
1035 static constexpr const char *
const DerefOpTag =
"DerefOp";
1036 static constexpr const char *
const AddOpTag =
"AddOp";
1037 static constexpr const char *
const OffsetTag =
"Offset";
1046 : FixableGadget(Kind::DerefSimplePtrArithFixable),
1056 ignoringImpCasts(
declRefExpr(toSupportedVariable()).
1057 bind(BaseDeclRefExprTag)));
1058 auto PlusOverPtrAndInteger =
expr(
anyOf(
1066 hasOperatorName(
"*"),
1067 hasUnaryOperand(ignoringParens(PlusOverPtrAndInteger)))
1072 virtual std::optional<FixItList>
getFixits(
const Strategy &
s)
const final;
1078 return {BaseDeclRefExpr};
1083static std::tuple<FixableGadgetList, WarningGadgetList, DeclUseTracker>
1085 bool EmitSuggestions) {
1088 FixableGadgetList FixableGadgets;
1089 WarningGadgetList WarningGadgets;
1090 DeclUseTracker Tracker;
1098 [[maybe_unused]]
int numFound = 0;
1099#define NEXT ++numFound
1102 if (
const auto *DRE = Result.Nodes.getNodeAs<
DeclRefExpr>(
"any_dre")) {
1103 Tracker.discoverUse(DRE);
1107 if (
const auto *DS = Result.Nodes.getNodeAs<
DeclStmt>(
"any_ds")) {
1108 Tracker.discoverDecl(DS);
1115#define FIXABLE_GADGET(name) \
1116 if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
1117 FixableGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
1120#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1121#define WARNING_GADGET(name) \
1122 if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
1123 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
1126#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1128 assert(numFound >= 1 &&
"Gadgets not found in match result!");
1129 assert(numFound <= 1 &&
"Conflicting bind tags in gadgets!");
1134 GadgetFinderCallback CB;
1139 forEachDescendantEvaluatedStmt(
stmt(
anyOf(
1142 allOf(x ## Gadget::matcher().bind(#x), \
1143 notInSafeBufferOptOut(&Handler)),
1144#include
"clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1153 if (EmitSuggestions) {
1159 x ## Gadget::matcher().bind(#x),
1160#include
"clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1177 return {std::move(CB.FixableGadgets), std::move(CB.WarningGadgets),
1178 std::move(CB.Tracker)};
1184 return N1->getBeginLoc().getRawEncoding() <
1185 N2->getBeginLoc().getRawEncoding();
1190 std::map<const VarDecl *, std::set<const WarningGadget *>,
1204 for (
auto &G : AllUnsafeOperations) {
1205 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
1207 bool AssociatedWithVarDecl =
false;
1208 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
1209 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1210 result.
byVar[VD].insert(G.get());
1211 AssociatedWithVarDecl =
true;
1215 if (!AssociatedWithVarDecl) {
1216 result.
noVar.push_back(G.get());
1224 std::map<const VarDecl *, std::set<const FixableGadget *>,
1234 for (
auto &F : AllFixableOperations) {
1235 DeclUseList DREs = F->getClaimedVarUseSites();
1238 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1239 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
1243 return FixablesForUnsafeVars;
1250 std::vector<const FixItHint *> All;
1254 std::sort(All.begin(), All.end(),
1256 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
1257 H2->RemoveRange.getBegin());
1265 Hint->RemoveRange.getBegin())) {
1277std::optional<FixItList>
1278PointerAssignmentGadget::getFixits(
const Strategy &S)
const {
1279 const auto *LeftVD = cast<VarDecl>(PtrLHS->
getDecl());
1280 const auto *RightVD = cast<VarDecl>(PtrRHS->
getDecl());
1281 switch (S.lookup(LeftVD)) {
1282 case Strategy::Kind::Span:
1283 if (S.lookup(RightVD) == Strategy::Kind::Span)
1285 return std::nullopt;
1286 case Strategy::Kind::Wontfix:
1287 return std::nullopt;
1288 case Strategy::Kind::Iterator:
1289 case Strategy::Kind::Array:
1290 case Strategy::Kind::Vector:
1291 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1293 return std::nullopt;
1296std::optional<FixItList>
1297PointerInitGadget::getFixits(
const Strategy &S)
const {
1298 const auto *LeftVD = PtrInitLHS;
1299 const auto *RightVD = cast<VarDecl>(PtrInitRHS->
getDecl());
1300 switch (S.lookup(LeftVD)) {
1301 case Strategy::Kind::Span:
1302 if (S.lookup(RightVD) == Strategy::Kind::Span)
1304 return std::nullopt;
1305 case Strategy::Kind::Wontfix:
1306 return std::nullopt;
1307 case Strategy::Kind::Iterator:
1308 case Strategy::Kind::Array:
1309 case Strategy::Kind::Vector:
1310 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1312 return std::nullopt;
1315std::optional<FixItList>
1316ULCArraySubscriptGadget::getFixits(
const Strategy &S)
const {
1317 if (
const auto *DRE =
1318 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts()))
1319 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
1320 switch (S.lookup(VD)) {
1321 case Strategy::Kind::Span: {
1326 if (
auto ConstVal =
Node->getIdx()->getIntegerConstantExpr(Ctx)) {
1327 if (ConstVal->isNegative())
1328 return std::nullopt;
1329 }
else if (!
Node->getIdx()->getType()->isUnsignedIntegerType())
1330 return std::nullopt;
1334 case Strategy::Kind::Wontfix:
1335 case Strategy::Kind::Iterator:
1336 case Strategy::Kind::Array:
1337 case Strategy::Kind::Vector:
1338 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1341 return std::nullopt;
1344static std::optional<FixItList>
1347std::optional<FixItList>
1348UPCAddressofArraySubscriptGadget::getFixits(
const Strategy &S)
const {
1349 auto DREs = getClaimedVarUseSites();
1350 const auto *VD = cast<VarDecl>(DREs.front()->getDecl());
1352 switch (S.lookup(VD)) {
1353 case Strategy::Kind::Span:
1355 case Strategy::Kind::Wontfix:
1356 case Strategy::Kind::Iterator:
1357 case Strategy::Kind::Array:
1358 case Strategy::Kind::Vector:
1359 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1361 return std::nullopt;
1366 static const char *
const EOL =
"\n";
1372 std::string
s = std::string(
"<# ");
1373 s += HintTextToUser;
1381 Val.toString(Txt, 10,
true);
1383 Txt.push_back(
'\0');
1388template <
typename NodeTy>
1389static std::optional<SourceLocation>
1398 return std::nullopt;
1402template <
typename NodeTy>
1412 return std::nullopt;
1419 std::optional<SourceLocation> LastCharLoc =
getPastLoc(E,
SM, LangOpts);
1426 return std::nullopt;
1439 return std::nullopt;
1451static std::optional<StringRef>
1460 return std::nullopt;
1461 return getRangeText({ParmIdentBeginLoc, ParmIdentEndLoc},
SM, LangOpts);
1474 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
1475 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
1476 VD->getBeginLoc())) &&
1477 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
1478 At->getRange().getBegin()));
1482 AttrRangeOverlapping;
1506static std::optional<std::string>
1509 std::optional<Qualifiers> *QualifiersToAppend) {
1514 "Expecting a VarDecl of type of pointer to object type");
1523 case TypeLoc::ConstantArray:
1524 case TypeLoc::IncompleteArray:
1525 case TypeLoc::VariableArray:
1526 case TypeLoc::DependentSizedArray:
1527 case TypeLoc::Decayed:
1528 assert(isa<ParmVarDecl>(VD) &&
"An array type shall not be treated as a "
1529 "pointer type unless it decays.");
1532 case TypeLoc::Pointer:
1536 return std::nullopt;
1541 return std::nullopt;
1549 return std::nullopt;
1556 if (!PteEndOfTokenLoc.
isValid())
1559 return std::nullopt;
1560 if (!
SM.isBeforeInTranslationUnit(PteEndOfTokenLoc, IdentLoc)) {
1567 return std::nullopt;
1602 std::optional<Qualifiers> Quals = std::nullopt) {
1603 const char *
const SpanOpen =
"std::span<";
1606 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
1607 return SpanOpen + EltTyText.str() +
'>';
1610std::optional<FixItList>
1612 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->
getDecl());
1614 if (VD &&
s.lookup(VD) == Strategy::Kind::Span) {
1618 if (ConstVal->isNegative())
1619 return std::nullopt;
1647 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
1649 return std::nullopt;
1654 std::optional<SourceLocation> AddOpLocation =
1656 std::optional<SourceLocation> DerefOpLocation =
1659 if (!AddOpLocation || !DerefOpLocation)
1660 return std::nullopt;
1670 return std::nullopt;
1673std::optional<FixItList>
1674PointerDereferenceGadget::getFixits(
const Strategy &S)
const {
1676 switch (S.lookup(VD)) {
1677 case Strategy::Kind::Span: {
1685 if (
auto LocPastOperand =
1692 case Strategy::Kind::Iterator:
1693 case Strategy::Kind::Array:
1694 case Strategy::Kind::Vector:
1695 llvm_unreachable(
"Strategy not implemented yet!");
1696 case Strategy::Kind::Wontfix:
1697 llvm_unreachable(
"Invalid strategy!");
1700 return std::nullopt;
1705std::optional<FixItList> UPCStandalonePointerGadget::getFixits(
const Strategy &S)
1707 const auto VD = cast<VarDecl>(
Node->getDecl());
1708 switch (S.lookup(VD)) {
1709 case Strategy::Kind::Span: {
1713 std::optional<SourceLocation> EndOfOperand =
1718 *EndOfOperand,
".data()")}};
1722 case Strategy::Kind::Wontfix:
1723 case Strategy::Kind::Iterator:
1724 case Strategy::Kind::Array:
1725 case Strategy::Kind::Vector:
1726 llvm_unreachable(
"unsupported strategies for FixableGadgets");
1729 return std::nullopt;
1734static std::optional<FixItList>
1736 const auto *ArraySub = cast<ArraySubscriptExpr>(
Node->getSubExpr());
1737 const auto *DRE = cast<DeclRefExpr>(ArraySub->getBase()->IgnoreImpCasts());
1741 const Expr *Idx = ArraySub->getIdx();
1744 std::stringstream SS;
1745 bool IdxIsLitZero =
false;
1748 if ((*ICE).isZero())
1749 IdxIsLitZero =
true;
1750 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
1752 return std::nullopt;
1756 SS << (*DreString).str() <<
".data()";
1758 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
1760 return std::nullopt;
1762 SS <<
"&" << (*DreString).str() <<
".data()"
1763 <<
"[" << (*IndexString).str() <<
"]";
1773 if (DREs.size() != 1)
1774 return std::nullopt;
1776 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
1777 if (S.lookup(VD) == Strategy::Kind::Span) {
1779 std::stringstream SS;
1781 StringRef varName = VD->
getName();
1785 SS <<
"(" << varName.data() <<
" = " << varName.data()
1786 <<
".subspan(1)).data()";
1787 std::optional<SourceLocation> PreIncLocation =
1789 if (!PreIncLocation)
1790 return std::nullopt;
1797 return std::nullopt;
1815 const StringRef UserFillPlaceHolder) {
1823 if (
Init->isNullPointerConstant(Ctx,
1827 NPC_ValueDependentIsNotNull)) {
1828 std::optional<SourceLocation> InitLocation =
1839 std::string ExtentText = UserFillPlaceHolder.data();
1840 StringRef One =
"1";
1845 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
1850 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
1851 if (!Ext->HasSideEffects(Ctx)) {
1852 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
1855 ExtentText = *ExtentString;
1857 }
else if (!CxxNew->isArray())
1862 Init->IgnoreImpCasts()->getType())) {
1870 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
1871 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
1872 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
1879 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
1884 StrBuffer.append(
", ");
1885 StrBuffer.append(ExtentText);
1886 StrBuffer.append(
"}");
1892#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
1893Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), "failed to produce fixit for declaration '" + (D)->getNameAsString() + "'" + (Msg))
1895#define DEBUG_NOTE_DECL_FAIL(D, Msg)
1905 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
1910 return std::nullopt;
1912 std::string SpanTyText =
"std::span<";
1914 SpanTyText.append(*PteTyText);
1916 if (PteTyQualifiers) {
1917 SpanTyText.append(
" ");
1918 SpanTyText.append(PteTyQualifiers->getAsString());
1920 SpanTyText.append(
">");
1939 const StringRef UserFillPlaceHolder,
1953 std::stringstream SS;
1963 std::optional<StringRef> IdentText =
1972 FixItList InitFixIts =
1974 if (InitFixIts.empty())
1976 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts.begin()),
1977 std::make_move_iterator(InitFixIts.end()));
1980 EndLocForReplacement =
Init->getBeginLoc().getLocWithOffset(-1);
1982 SS <<
" " << IdentText->str();
1983 if (!EndLocForReplacement.
isValid()) {
2027static std::optional<FixItList>
2033 return std::nullopt;
2038 std::vector<std::string> NewTysTexts(NumParms);
2039 std::vector<bool> ParmsMask(NumParms,
false);
2040 bool AtLeastOneParmToFix =
false;
2042 for (
unsigned i = 0; i < NumParms; i++) {
2045 if (S.lookup(PVD) == Strategy::Kind::Wontfix)
2047 if (S.lookup(PVD) != Strategy::Kind::Span)
2049 return std::nullopt;
2051 std::optional<Qualifiers> PteTyQuals = std::nullopt;
2052 std::optional<std::string> PteTyText =
2057 return std::nullopt;
2060 ParmsMask[i] =
true;
2061 AtLeastOneParmToFix =
true;
2063 if (!AtLeastOneParmToFix)
2070 const auto NewOverloadSignatureCreator =
2071 [&
SM, &LangOpts, &NewTysTexts,
2072 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
2073 std::stringstream SS;
2081 SS << Prefix->str();
2083 return std::nullopt;
2087 for (
unsigned i = 0; i < NumParms; i++) {
2095 SS << NewTysTexts[i];
2098 SS <<
' ' << II->
getName().str();
2103 SS << ParmTypeText->str();
2105 return std::nullopt;
2106 if (i != NumParms - 1)
2115 const auto OldOverloadDefCreator =
2116 [&Handler, &
SM, &LangOpts, &NewTysTexts,
2117 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
2118 std::stringstream SS;
2126 << FDPrefix->str() <<
"{";
2128 return std::nullopt;
2131 SS <<
"return " << FunQualName->str() <<
"(";
2133 return std::nullopt;
2137 for (
unsigned i = 0; i < NumParms; i++) {
2146 return std::nullopt;
2153 if (i != NumParms - 1)
2164 std::optional<SourceLocation> Loc =
getPastLoc(FReDecl,
SM, LangOpts);
2168 if (FReDecl->isThisDeclarationADefinition()) {
2169 assert(FReDecl == FD &&
"inconsistent function definition");
2172 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
2178 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
2181 FReDecl->getBeginLoc(),
" ")));
2184 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
2206 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
2222 std::stringstream SS;
2225 if (PteTyQualifiers)
2234 SS <<
' ' << PVDNameText->str();
2240 const DeclUseTracker &Tracker,
2243 const DeclStmt *DS = Tracker.lookupDecl(VD);
2267 const DeclUseTracker &Tracker,
ASTContext &Ctx,
2269 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
2270 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
2271 if (!FD || FD != D) {
2282 if (FD->isMain() || FD->isConstexpr() ||
2283 FD->getTemplatedKind() != FunctionDecl::TemplatedKind::TK_NonTemplate ||
2286 isa<CXXMethodDecl>(FD) ||
2288 (FD->hasBody() && isa<CXXTryStmt>(FD->getBody())) ||
2289 FD->isOverloadedOperator()) {
2296 case Strategy::Kind::Span: {
2298 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
2307 case Strategy::Kind::Iterator:
2308 case Strategy::Kind::Array:
2309 case Strategy::Kind::Vector:
2310 llvm_unreachable(
"Strategy not implemented yet!");
2311 case Strategy::Kind::Wontfix:
2312 llvm_unreachable(
"Invalid strategy!");
2314 llvm_unreachable(
"Unknown strategy!");
2322 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
2324 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
2333 return isa<ParmVarDecl>(VD) &&
2341 std::map<const VarDecl *, FixItList> &FixItsForVariable,
2346 for (
const auto &[VD, Ignore] : FixItsForVariable) {
2348 if (llvm::any_of(Grp,
2349 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
2350 return !FixItsForVariable.count(GrpMember);
2355 ToErase.push_back(
Member);
2358 for (
auto *VarToErase : ToErase)
2359 FixItsForVariable.erase(VarToErase);
2370 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
2373 FixItList FixItsSharedByParms{};
2375 std::optional<FixItList> OverloadFixes =
2378 if (OverloadFixes) {
2379 FixItsSharedByParms.append(*OverloadFixes);
2385 FixItsForVariable.erase(
Member);
2387 return FixItsSharedByParms;
2391static std::map<const VarDecl *, FixItList>
2400 std::map<const VarDecl *, FixItList> FixItsForVariable;
2405 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
2406 FixItsForVariable[VD] =
2407 fixVariable(VD, S.lookup(VD), D, Tracker, Ctx, Handler);
2410 if (FixItsForVariable[VD].empty()) {
2411 FixItsForVariable.erase(VD);
2414 for (
const auto &F : Fixables) {
2415 std::optional<FixItList> Fixits = F->getFixits(S);
2418 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
2419 Fixits->begin(), Fixits->end());
2425 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
2428 FixItsForVariable.erase(VD);
2447 FixItList FixItsSharedByParms{};
2449 if (
auto *FD = dyn_cast<FunctionDecl>(D))
2451 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
2455 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
2458 for (
auto &[Var, Ignore] : FixItsForVariable) {
2459 bool AnyParm =
false;
2460 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
2462 for (
const VarDecl *GrpMate : VarGroupForVD) {
2465 if (FixItsForVariable.count(GrpMate))
2466 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
2470 assert(!FixItsSharedByParms.empty() &&
2471 "Should not try to fix a parameter that does not belong to a "
2473 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
2480 for (
auto Iter = FinalFixItsForVariable.begin();
2481 Iter != FinalFixItsForVariable.end();)
2484 Iter = FinalFixItsForVariable.erase(
Iter);
2487 return FinalFixItsForVariable;
2490template <
typename VarDeclIterTy>
2494 for (
const VarDecl *VD : UnsafeVars) {
2495 S.set(VD, Strategy::Kind::Span);
2502 const std::vector<VarGrpTy> Groups;
2503 const std::map<const VarDecl *, unsigned> &VarGrpMap;
2504 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
2508 const std::vector<VarGrpTy> &Groups,
2509 const std::map<const VarDecl *, unsigned> &VarGrpMap,
2510 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
2511 : Groups(Groups), VarGrpMap(VarGrpMap),
2512 GrpsUnionForParms(GrpsUnionForParms) {}
2515 if (GrpsUnionForParms.contains(Var)) {
2518 return GrpsUnionForParms.getArrayRef();
2523 auto It = VarGrpMap.find(Var);
2525 if (It == VarGrpMap.end())
2526 return std::nullopt;
2527 return Groups[It->second];
2531 return GrpsUnionForParms.getArrayRef();
2537 bool EmitSuggestions) {
2546 if (
const auto *fd = dyn_cast<CXXMethodDecl>(D)) {
2547 if (fd->getParent()->isLambda() && fd->getParent()->isLocalClass())
2553 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
2555 if (FReDecl->isExternC()) {
2556 EmitSuggestions =
false;
2565 auto [FixableGadgets, WarningGadgets, Tracker] =
2568 if (!EmitSuggestions) {
2572 for (
const auto &G : WarningGadgets) {
2579 assert(FixableGadgets.size() == 0 &&
2580 "Fixable gadgets found but suggestions not requested!");
2586 if (!WarningGadgets.empty()) {
2590 for (
const auto &G : FixableGadgets) {
2591 for (
const auto *DRE : G->getClaimedVarUseSites()) {
2592 Tracker.claimUse(DRE);
2608 if (WarningGadgets.empty())
2614 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
2617 for (
auto it = FixablesForAllVars.
byVar.cbegin();
2618 it != FixablesForAllVars.
byVar.cend();) {
2620 if ((!it->first->isLocalVarDecl() && !isa<ParmVarDecl>(it->first))) {
2623 it->first, it->first->getBeginLoc(),
2624 (
"failed to produce fixit for '" + it->first->getNameAsString() +
2625 "' : neither local nor a parameter"));
2627 it = FixablesForAllVars.
byVar.erase(it);
2628 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
2631 (
"failed to produce fixit for '" +
2632 it->first->getNameAsString() +
2633 "' : has a reference type"));
2635 it = FixablesForAllVars.
byVar.erase(it);
2636 }
else if (Tracker.hasUnclaimedUses(it->first)) {
2638 auto AllUnclaimed = Tracker.getUnclaimedUses(it->first);
2639 for (
auto UnclaimedDRE : AllUnclaimed) {
2640 std::string UnclaimedUseTrace =
2644 it->first, UnclaimedDRE->getBeginLoc(),
2645 (
"failed to produce fixit for '" + it->first->getNameAsString() +
2646 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
2647 UnclaimedUseTrace));
2650 it = FixablesForAllVars.
byVar.erase(it);
2651 }
else if (it->first->isInitCapture()) {
2654 it->first, it->first->getBeginLoc(),
2655 (
"failed to produce fixit for '" + it->first->getNameAsString() +
2656 "' : init capture"));
2658 it = FixablesForAllVars.
byVar.erase(it);
2665 using DepMapTy = DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
2666 DepMapTy DependenciesMap{};
2667 DepMapTy PtrAssignmentGraph{};
2669 for (
auto it : FixablesForAllVars.
byVar) {
2670 for (
const FixableGadget *fixable : it.second) {
2671 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
2672 fixable->getStrategyImplications();
2674 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
2675 PtrAssignmentGraph[Impl.first].insert(Impl.second);
2697 std::set<const VarDecl *> VisitedVarsDirected{};
2698 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
2699 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
2701 std::queue<const VarDecl*> QueueDirected{};
2702 QueueDirected.push(Var);
2703 while(!QueueDirected.empty()) {
2704 const VarDecl* CurrentVar = QueueDirected.front();
2705 QueueDirected.pop();
2706 VisitedVarsDirected.insert(CurrentVar);
2707 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
2708 for (
const VarDecl *Adj : AdjacentNodes) {
2709 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
2710 QueueDirected.push(Adj);
2712 DependenciesMap[Var].insert(Adj);
2713 DependenciesMap[Adj].insert(Var);
2720 std::vector<VarGrpTy> Groups;
2724 std::map<const VarDecl *, unsigned> VarGrpMap;
2726 llvm::SetVector<const VarDecl *>
2731 std::set<const VarDecl *> VisitedVars{};
2732 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
2733 if (VisitedVars.find(Var) == VisitedVars.end()) {
2734 VarGrpTy &VarGroup = Groups.emplace_back();
2735 std::queue<const VarDecl*> Queue{};
2738 while(!Queue.empty()) {
2739 const VarDecl* CurrentVar = Queue.front();
2741 VisitedVars.insert(CurrentVar);
2742 VarGroup.push_back(CurrentVar);
2743 auto AdjacentNodes = DependenciesMap[CurrentVar];
2744 for (
const VarDecl *Adj : AdjacentNodes) {
2745 if (VisitedVars.find(Adj) == VisitedVars.end()) {
2751 bool HasParm =
false;
2752 unsigned GrpIdx = Groups.size() - 1;
2754 for (
const VarDecl *
V : VarGroup) {
2755 VarGrpMap[
V] = GrpIdx;
2760 GrpsUnionForParms.insert(VarGroup.begin(), VarGroup.end());
2782 for (
auto I = FixablesForAllVars.
byVar.begin();
2783 I != FixablesForAllVars.
byVar.end();) {
2785 if (!VisitedVars.count((*I).first)) {
2787 I = FixablesForAllVars.
byVar.erase(I);
2795 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
2797 return FixablesForAllVars.
byVar.count(
V);
2801 if (isa<NamedDecl>(D))
2804 FixItsForVariableGroup =
2806 Tracker, Handler, VarGrpMgr);
2808 for (
const auto &G : UnsafeOps.
noVar) {
2812 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
2813 auto FixItsIt = FixItsForVariableGroup.find(VD);
2815 FixItsIt != FixItsForVariableGroup.end()
2816 ? std::move(FixItsIt->second)
2819 for (
const auto &G : WarningGadgets) {
BoundNodesTreeBuilder Nodes
#define AST_MATCHER(Type, DefineMatcher)
AST_MATCHER(Type, DefineMatcher) { ... } defines a zero parameter function named DefineMatcher() that...
#define AST_MATCHER_P(Type, DefineMatcher, ParamType, Param)
AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) { ... } defines a single-parameter function name...
static Decl::Kind getKind(const Decl *D)
static const Decl * getCanonicalDecl(const Decl *D)
llvm::DenseMap< Stmt *, Stmt * > MapTy
Defines the clang::Preprocessor interface.
static bool hasAttr(const Decl *D, bool IgnoreImplicitAttr)
static FixItList fixVariableWithSpan(const VarDecl *VD, const DeclUseTracker &Tracker, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static std::optional< FixItList > fixUPCAddressofArraySubscriptWithSpan(const UnaryOperator *Node)
static FixItList createFunctionOverloadsForParms(std::map< const VarDecl *, FixItList > &FixItsForVariable, const VariableGroupsManager &VarGrpMgr, const FunctionDecl *FD, const Strategy &S, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
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< SourceLocation > getEndCharLoc(const NodeTy *Node, const SourceManager &SM, const LangOptions &LangOpts)
static Strategy getNaiveStrategy(llvm::iterator_range< VarDeclIterTy > UnsafeVars)
static std::string getSpanTypeText(StringRef EltTyText, std::optional< Qualifiers > Quals=std::nullopt)
static FixItList FixVarInitializerWithSpan(const Expr *Init, ASTContext &Ctx, const StringRef UserFillPlaceHolder)
static FixItList fixLocalVarDeclWithSpan(const VarDecl *D, ASTContext &Ctx, const StringRef UserFillPlaceHolder, UnsafeBufferUsageHandler &Handler)
static SourceRange getSourceRangeToTokenEnd(const Decl *D, const SourceManager &SM, LangOptions LangOpts)
#define FIXABLE_GADGET(name)
static FixItList fixVariable(const VarDecl *VD, Strategy::Kind K, const Decl *D, const DeclUseTracker &Tracker, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
#define WARNING_GADGET(name)
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 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)
static std::map< const VarDecl *, FixItList > getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S, ASTContext &Ctx, const Decl *D, const DeclUseTracker &Tracker, UnsafeBufferUsageHandler &Handler, const VariableGroupsManager &VarGrpMgr)
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 overlapWithMacro(const FixItList &FixIts)
static bool hasUnsupportedSpecifiers(const VarDecl *VD, const SourceManager &SM)
#define DEBUG_NOTE_DECL_FAIL(D, Msg)
static std::optional< FixItList > createOverloadsForFixedParams(const Strategy &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::string getAPIntText(APInt Val)
static std::optional< StringRef > getFunNameText(const FunctionDecl *FD, const SourceManager &SM, const LangOptions &LangOpts)
__device__ __2f16 float __ockl_bool s
DerefSimplePtrArithFixableGadget(const MatchFinder::MatchResult &Result)
virtual const Stmt * getBaseStmt() const final
virtual std::optional< FixItList > getFixits(const Strategy &s) const final
virtual DeclUseList getClaimedVarUseSites() const final
virtual const Stmt * getBaseStmt() const override
virtual DeclUseList getClaimedVarUseSites() const override
static bool classof(const Gadget *G)
UPCPreIncrementGadget(const MatchFinder::MatchResult &Result)
virtual std::optional< FixItList > getFixits(const Strategy &S) const override
VariableGroupsManagerImpl(const std::vector< VarGrpTy > &Groups, const std::map< const VarDecl *, unsigned > &VarGrpMap, const llvm::SetVector< const VarDecl * > &GrpsUnionForParms)
VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm) const override
Returns the set of variables (including Var) that need to be fixed together in one step.
VarGrpRef getGroupOfParms() const override
Returns the non-empty group of variables that include parameters of the analyzing function,...
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
const ConstantArrayType * getAsConstantArrayType(QualType T) const
DynTypedNodeList getParents(const NodeT &Node)
Forwards to get node parents from the ParentMapContext.
const LangOptions & getLangOpts() const
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Attr - This represents one attribute.
A builtin binary operation expression such as "x + y" or "x <= y".
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
Represents a C++11 noexcept expression (C++ [expr.unary.noexcept]).
A C++ typeid expression (C++ [expr.typeid]), which gets the type_info that corresponds to the supplie...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
static const char * getCastKindName(CastKind CK)
Represents a character-granular source range.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getEnd() const
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
bool isSingleResult() const
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
A reference to a declared variable, function, enum, etc.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
bool isSingleDecl() const
isSingleDecl - This method returns true if this DeclStmt refers to a single Decl.
Decl - This represents one declaration (or definition), e.g.
SourceLocation getEndLoc() const LLVM_READONLY
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
SourceLocation getLocation() const
DeclContext * getDeclContext()
SourceLocation getBeginLoc() const LLVM_READONLY
NestedNameSpecifier * getQualifier() const
Retrieve the nested-name-specifier that qualifies the name of this declaration, if it was present in ...
SourceLocation 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.
This represents one expression.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
NullPointerConstantValueDependence
Enumeration used to describe how isNullPointerConstant() should cope with value-dependent expressions...
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 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.
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.
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
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.
Stmt - This represents one statement.
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.
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...
virtual void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl)=0
Invoked when an unsafe operation over raw pointers is found.
void addDebugNoteForVar(const VarDecl *VD, SourceLocation Loc, std::string Text)
virtual std::string getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, StringRef WSSuffix="") const =0
virtual void handleUnsafeVariableGroup(const VarDecl *Variable, const VariableGroupsManager &VarGrpMgr, FixItList &&Fixes, const Decl *D)=0
Invoked when a fix is suggested against a variable.
Represents a variable declaration or definition.
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
VarDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
bool isInlineSpecified() const
bool hasConstantInitialization() const
Determine whether this variable has constant initialization.
const Expr * getInit() const
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
virtual VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm=nullptr) const =0
Returns the set of variables (including Var) that need to be fixed together in one step.
virtual VarGrpRef getGroupOfParms() const =0
Returns the non-empty group of variables that include parameters of the analyzing function,...
bool findMatch(const DynTypedNode &DynNode)
bool shouldVisitImplicitCode() const
bool TraverseDecl(Decl *Node)
bool TraverseCXXNoexceptExpr(CXXNoexceptExpr *Node)
RecursiveASTVisitor< MatchDescendantVisitor > VisitorBase
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc Node)
bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node)
MatchDescendantVisitor(const internal::DynTypedMatcher *Matcher, internal::ASTMatchFinder *Finder, internal::BoundNodesTreeBuilder *Builder, internal::ASTMatchFinder::BindKind Bind, const bool ignoreUnevaluatedContext)
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc Node)
bool shouldVisitTemplateInstantiations() const
bool TraverseCXXTypeidExpr(CXXTypeidExpr *Node)
bool TraverseStmt(Stmt *Node, DataRecursionQueue *Queue=nullptr)
bool TraverseGenericSelectionExpr(GenericSelectionExpr *Node)
Called when the Match registered for it was successfully found in the AST.
virtual void run(const MatchResult &Result)=0
Called on every match by the MatchFinder.
A class to allow finding matches over the Clang AST.
void addMatcher(const DeclarationMatcher &NodeMatch, MatchCallback *Action)
Adds a matcher to execute when running over the AST.
void match(const T &Node, ASTContext &Context)
Calls the registered callbacks on all matches on the given Node.
const internal::VariadicDynCastAllOfMatcher< Decl, VarDecl > varDecl
Matches variable declarations.
const internal::VariadicDynCastAllOfMatcher< Stmt, DeclRefExpr > declRefExpr
Matches expressions that refer to declarations.
const AstTypeMatcher< EnumType > enumType
Matches enum types.
static auto isInUnspecifiedLvalueContext(internal::Matcher< Expr > innerMatcher)
const internal::VariadicOperatorMatcherFunc< 1, 1 > unless
Matches if the provided matcher does not match.
const internal::VariadicDynCastAllOfMatcher< Stmt, ImplicitCastExpr > implicitCastExpr
Matches the implicit cast nodes of Clang's AST.
const AstTypeMatcher< PointerType > pointerType
Matches pointer types, but does not match Objective-C object pointer types.
const internal::VariadicDynCastAllOfMatcher< Decl, BindingDecl > bindingDecl
Matches binding declarations Example matches foo and bar (matcher = bindingDecl()
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, 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::ArgumentAdaptingMatcherFunc< internal::HasMatcher > has
Matches AST nodes that have child AST nodes that match the provided matcher.
internal::PolymorphicMatcher< internal::ValueEqualsMatcher, void(internal::AllNodeBaseTypes), ValueT > equals(const ValueT &Value)
Matches literals that are equal to the given value of type ValueT.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> eachOf
Matches if any of the given matchers matches.
static internal::Matcher< Stmt > isInUnspecifiedPointerContext(internal::Matcher< Stmt > InnerMatcher)
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> allOf
Matches if all given matchers match.
const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl
Matches function declarations.
static auto hasPointerType()
const internal::VariadicDynCastAllOfMatcher< Stmt, IntegerLiteral > integerLiteral
Matches integer literals of all sizes / encodings, e.g.
const internal::VariadicDynCastAllOfMatcher< Stmt, DeclStmt > declStmt
Matches declaration statements.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
const internal::VariadicFunction< internal::PolymorphicMatcher< internal::HasAnyOperatorNameMatcher, AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr, CXXRewrittenBinaryOperator, UnaryOperator), std::vector< std::string > >, StringRef, internal::hasAnyOperatorNameFunc > hasAnyOperatorName
Matches operator expressions (binary or unary) that have any of the specified names.
const internal::VariadicDynCastAllOfMatcher< Stmt, CastExpr > castExpr
Matches any cast nodes of Clang's AST.
const internal::VariadicDynCastAllOfMatcher< Stmt, IfStmt > ifStmt
Matches if statements.
bool anyConflict(const llvm::SmallVectorImpl< FixItHint > &FixIts, const SourceManager &SM)
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
std::vector< const VarDecl * > VarGrpTy
YAML serialization mapping.
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
Contains all information for a given match.