23#include "llvm/ADT/APSInt.h"
24#include "llvm/ADT/SmallVector.h"
25#include "llvm/ADT/StringRef.h"
26#include "llvm/Support/Casting.h"
34using namespace ast_matchers;
41 std::string VisitStmt(
const Stmt *S) {
return S->getStmtClassName(); }
44 return "BinaryOperator(" + BO->
getOpcodeStr().str() +
")";
58static std::string getDREAncestorString(
const DeclRefExpr *DRE,
62 StmtDebugPrinter StmtPriner;
65 SS << StmtPriner.Visit(St);
69 if (StParents.
size() > 1)
70 return "unavailable due to multiple parents";
71 if (StParents.
size() == 0)
91 internal::ASTMatchFinder *Finder,
92 internal::BoundNodesTreeBuilder *Builder,
93 internal::ASTMatchFinder::BindKind Bind,
94 const bool ignoreUnevaluatedContext)
95 : Matcher(Matcher), Finder(Finder), Builder(Builder), Bind(Bind),
96 Matches(
false), ignoreUnevaluatedContext(ignoreUnevaluatedContext) {
107 *Builder = ResultBindings;
126 if (isa<FunctionDecl, BlockDecl, ObjCMethodDecl>(
Node))
134 if (ignoreUnevaluatedContext)
136 return DynamicRecursiveASTVisitor::TraverseGenericSelectionExpr(
Node);
142 if (ignoreUnevaluatedContext)
144 return DynamicRecursiveASTVisitor::TraverseUnaryExprOrTypeTraitExpr(
Node);
149 if (ignoreUnevaluatedContext)
151 return DynamicRecursiveASTVisitor::TraverseTypeOfExprTypeLoc(
Node);
156 if (ignoreUnevaluatedContext)
158 return DynamicRecursiveASTVisitor::TraverseDecltypeTypeLoc(
Node);
163 if (ignoreUnevaluatedContext)
165 return DynamicRecursiveASTVisitor::TraverseCXXNoexceptExpr(
Node);
170 if (ignoreUnevaluatedContext)
172 return DynamicRecursiveASTVisitor::TraverseCXXTypeidExpr(
Node);
178 return DynamicRecursiveASTVisitor::TraverseCXXDefaultInitExpr(
Node);
194 template <
typename T>
bool match(
const T &
Node) {
195 internal::BoundNodesTreeBuilder RecursiveBuilder(*Builder);
198 &RecursiveBuilder)) {
199 ResultBindings.addMatch(RecursiveBuilder);
201 if (Bind != internal::ASTMatchFinder::BK_All)
207 const internal::DynTypedMatcher *
const Matcher;
208 internal::ASTMatchFinder *
const Finder;
209 internal::BoundNodesTreeBuilder *
const Builder;
210 internal::BoundNodesTreeBuilder ResultBindings;
211 const internal::ASTMatchFinder::BindKind Bind;
213 bool ignoreUnevaluatedContext;
225 const DynTypedMatcher &DTM =
static_cast<DynTypedMatcher
>(innerMatcher);
234 const DynTypedMatcher &DTM =
static_cast<DynTypedMatcher
>(innerMatcher);
244 return !Handler->isSafeBufferOptOut(
Node.getBeginLoc());
249 return Handler->ignoreUnsafeBufferInContainer(
Node.getBeginLoc());
254 if (Finder->getASTContext().getLangOpts().CPlusPlus)
255 return Handler->ignoreUnsafeBufferInLibcCall(
Node.getBeginLoc());
260 return innerMatcher.matches(*
Node.getSubExpr(), Finder, Builder);
265 return Node.getOpcode() == UnaryOperator::Opcode::UO_PreInc;
275 hasCastKind(CastKind::CK_LValueToRValue),
276 castSubExpr(innerMatcher)),
287static internal::Matcher<Stmt>
299 forEachArgumentWithParamType(
305 auto CastOperandMatcher =
307 hasCastKind(CastKind::CK_PointerToBoolean)),
310 auto CompOperandMatcher =
316 auto PtrSubtractionMatcher =
323 eachOf(hasLHS(InnerMatcher),
324 hasRHS(InnerMatcher)));
327 return stmt(
anyOf(CallArgMatcher, CastOperandMatcher, CompOperandMatcher,
328 PtrSubtractionMatcher));
343static internal::Matcher<Stmt>
350 auto IfStmtThen =
ifStmt(hasThen(InnerMatcher));
351 auto IfStmtElse =
ifStmt(hasElse(InnerMatcher));
353 return stmt(
anyOf(CompStmt, IfStmtThen, IfStmtElse));
366 assert(
Node.getNumArgs() == 2 &&
367 "expecting a two-parameter std::span constructor");
368 const Expr *Arg0 =
Node.getArg(0)->IgnoreImplicit();
369 const Expr *Arg1 =
Node.getArg(1)->IgnoreImplicit();
370 auto HaveEqualConstantValues = [&Finder](
const Expr *E0,
const Expr *E1) {
372 if (
auto E1CV = E1->getIntegerConstantExpr(Finder->getASTContext())) {
373 return APSInt::compareValues(*E0CV, *E1CV) == 0;
377 auto AreSameDRE = [](
const Expr *E0,
const Expr *E1) {
378 if (
auto *DRE0 = dyn_cast<DeclRefExpr>(E0))
379 if (
auto *DRE1 = dyn_cast<DeclRefExpr>(E1)) {
380 return DRE0->getDecl() == DRE1->getDecl();
384 std::optional<APSInt> Arg1CV =
387 if (Arg1CV && Arg1CV->isZero())
391 case Stmt::CXXNewExprClass:
392 if (
auto Size = cast<CXXNewExpr>(Arg0)->getArraySize()) {
394 return AreSameDRE((*Size)->IgnoreImplicit(), Arg1) ||
395 HaveEqualConstantValues(*Size, Arg1);
398 if (!cast<CXXNewExpr>(Arg0)->hasPlaceholderType()) {
400 return Arg1CV && Arg1CV->isOne();
403 case Stmt::UnaryOperatorClass:
404 if (cast<UnaryOperator>(Arg0)->getOpcode() ==
405 UnaryOperator::Opcode::UO_AddrOf)
407 return Arg1CV && Arg1CV->isOne();
409 case Stmt::CallExprClass:
410 if (
const auto *CE = dyn_cast<CallExpr>(Arg0)) {
411 const auto FnDecl = CE->getDirectCallee();
412 if (FnDecl && FnDecl->getNameAsString() ==
"addressof" &&
413 FnDecl->isInStdNamespace()) {
414 return Arg1CV && Arg1CV->isOne();
424 if (
auto *ConstArrTy =
425 Finder->getASTContext().getAsConstantArrayType(Arg0Ty)) {
426 const APSInt ConstArrSize =
APSInt(ConstArrTy->getSize());
429 return Arg1CV && APSInt::compareValues(ConstArrSize, *Arg1CV) == 0;
443 if (
const auto *CATy =
444 dyn_cast<ConstantArrayType>(
Node.getBase()
445 ->IgnoreParenImpCasts()
447 ->getUnqualifiedDesugaredType())) {
448 limit = CATy->getLimitedSize();
449 }
else if (
const auto *SLiteral = dyn_cast<StringLiteral>(
450 Node.getBase()->IgnoreParenImpCasts())) {
451 limit = SLiteral->getLength() + 1;
456 if (
const auto *IdxLit = dyn_cast<IntegerLiteral>(
Node.getIdx())) {
457 const APInt ArrIdx = IdxLit->getValue();
458 if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit)
465 return Node.getNumArgs() ==
Num;
468namespace libc_func_matchers {
484 StringRef
matchName(StringRef FunName,
bool isBuiltin) {
486 if (isBuiltin && FunName.starts_with(
"__builtin_"))
490 FunName.drop_front(10 ));
492 if (FunName.starts_with(
"__asan_"))
500 if (Name.starts_with(
"__") && Name.ends_with(
"_chk"))
502 Name.drop_front(2).drop_back(4) );
507 if (Name.ends_with(
"_s"))
508 return Name.drop_back(2 );
541 bool isKprintf =
false) {
542 class StringFormatStringHandler
546 const Expr *&UnsafeArg;
549 StringFormatStringHandler(
const CallExpr *
Call,
unsigned FmtArgIdx,
550 const Expr *&UnsafeArg)
551 :
Call(
Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg) {}
554 const char *startSpecifier,
555 unsigned specifierLen,
557 if (FS.getConversionSpecifier().getKind() ==
558 analyze_printf::PrintfConversionSpecifier::sArg) {
559 unsigned ArgIdx = FS.getPositionalArgIndex() + FmtArgIdx;
561 if (0 < ArgIdx && ArgIdx < Call->getNumArgs())
563 UnsafeArg =
Call->getArg(ArgIdx);
572 const Expr *Fmt =
Call->getArg(FmtArgIdx);
577 if (SL->getCharByteWidth() == 1)
578 FmtStr = SL->getString();
579 else if (
auto EvaledFmtStr = SL->tryEvaluateString(Ctx))
580 FmtStr = *EvaledFmtStr;
582 goto CHECK_UNSAFE_PTR;
584 StringFormatStringHandler Handler(
Call, FmtArgIdx, UnsafeArg);
587 Handler, FmtStr.begin(), FmtStr.end(), Ctx.
getLangOpts(),
595 llvm::make_range(
Call->arg_begin() + FmtArgIdx,
Call->arg_end()),
596 [&UnsafeArg](
const Expr *Arg) ->
bool {
597 if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg)) {
615 static std::unique_ptr<std::set<StringRef>> PredefinedNames =
nullptr;
616 if (!PredefinedNames)
618 std::make_unique<std::set<StringRef>, std::set<StringRef>>({
690 auto *II =
Node.getIdentifier();
696 II->getName(),
Node.getBuiltinID());
699 if (PredefinedNames->find(Name) != PredefinedNames->end())
702 std::string NameWCS = Name.str();
703 size_t WcsPos = NameWCS.find(
"wcs");
705 while (WcsPos != std::string::npos) {
706 NameWCS[WcsPos++] =
's';
707 NameWCS[WcsPos++] =
't';
708 NameWCS[WcsPos++] =
'r';
709 WcsPos = NameWCS.find(
"wcs", WcsPos);
711 if (PredefinedNames->find(NameWCS) != PredefinedNames->end())
715 return Name.ends_with(
"scanf");
722 auto *II =
Node.getIdentifier();
728 II->getName(),
Node.getBuiltinID());
730 if (!Name.ends_with(
"printf"))
732 return Name.starts_with(
"v");
738 auto *II =
Node.getIdentifier();
744 II->getName(),
Node.getBuiltinID());
746 if (!Name.ends_with(
"printf") ||
748 Name.starts_with(
"v"))
751 StringRef Prefix = Name.drop_back(6);
753 if (Prefix.ends_with(
"w"))
754 Prefix = Prefix.drop_back(1);
755 return Prefix ==
"s";
762 auto *II =
Node.getIdentifier();
768 II->getName(),
Node.getBuiltinID());
770 if (!Name.ends_with(
"printf") || Name.starts_with(
"v"))
773 StringRef Prefix = Name.drop_back(6);
775 if (Prefix.ends_with(
"w"))
776 Prefix = Prefix.drop_back(1);
778 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
786 clang::ast_matchers::internal::Matcher<Expr>,
787 UnsafeStringArgMatcher) {
791 assert(FD &&
"It should have been checked that FD is non-null.");
810 const Expr *UnsafeArg;
813 return UnsafeStringArgMatcher.matches(*UnsafeArg, Finder, Builder);
819 bool isKprintf =
false;
820 const Expr *UnsafeArg;
823 isKprintf = II->getName() ==
"kprintf";
825 return UnsafeStringArgMatcher.matches(*UnsafeArg, Finder, Builder);
835 const Expr *UnsafeArg;
838 return UnsafeStringArgMatcher.matches(*UnsafeArg, Finder, Builder);
844 for (
auto Arg :
Node.arguments())
846 if (UnsafeStringArgMatcher.matches(*Arg, Finder, Builder))
870 assert(FD &&
"It should have been checked that FD is non-null.");
881 const Expr *Buf =
Node.getArg(0), *Size =
Node.getArg(1);
884 !Size->getType()->isIntegerType())
888 static StringRef SizedObjs[] = {
"span",
"array",
"vector",
889 "basic_string_view",
"basic_string"};
891 Size = Size->IgnoreParenImpCasts();
892 if (
auto *MCEPtr = dyn_cast<CXXMemberCallExpr>(Buf))
893 if (
auto *MCESize = dyn_cast<CXXMemberCallExpr>(Size)) {
894 auto *DREOfPtr = dyn_cast<DeclRefExpr>(
895 MCEPtr->getImplicitObjectArgument()->IgnoreParenImpCasts());
896 auto *DREOfSize = dyn_cast<DeclRefExpr>(
897 MCESize->getImplicitObjectArgument()->IgnoreParenImpCasts());
899 if (!DREOfPtr || !DREOfSize)
901 if (DREOfPtr->getDecl() != DREOfSize->getDecl())
903 if (MCEPtr->getMethodDecl()->getName() !=
"data")
906 if (MCESize->getMethodDecl()->getName() ==
"size_bytes" ||
911 MCESize->getMethodDecl()->getName() ==
"size")
912 for (StringRef SizedObj : SizedObjs)
913 if (MCEPtr->getRecordDecl()->isInStdNamespace() &&
914 MCEPtr->getRecordDecl()->getCanonicalDecl()->getName() ==
928 if (Size->EvaluateAsConstantExpr(ER, Ctx)) {
931 return APSInt::compareValues(EVal,
APSInt(CAT->getSize(),
true)) != 0;
962#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
968 using Matcher =
decltype(
stmt());
970 Gadget(Kind K) : K(K) {}
975 StringRef getDebugName()
const {
980#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
982 llvm_unreachable(
"Unhandled Gadget::Kind enum");
986 virtual bool isWarningGadget()
const = 0;
994 virtual DeclUseList getClaimedVarUseSites()
const = 0;
996 virtual ~Gadget() =
default;
1004class WarningGadget :
public Gadget {
1006 WarningGadget(Kind K) : Gadget(K) {}
1008 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1009 bool isWarningGadget() const final {
return true; }
1012 bool IsRelatedToDecl,
1020class FixableGadget :
public Gadget {
1022 FixableGadget(Kind K) : Gadget(K) {}
1024 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1025 bool isWarningGadget() const final {
return false; }
1030 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1031 return std::nullopt;
1040 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1041 getStrategyImplications()
const {
1042 return std::nullopt;
1046static auto toSupportedVariable() {
return to(
varDecl()); }
1048using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1049using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1053class IncrementGadget :
public WarningGadget {
1054 static constexpr const char *
const OpTag =
"op";
1059 : WarningGadget(
Kind::Increment),
1062 static bool classof(
const Gadget *G) {
1063 return G->getKind() == Kind::Increment;
1066 static Matcher matcher() {
1074 bool IsRelatedToDecl,
1080 DeclUseList getClaimedVarUseSites()
const override {
1082 if (
const auto *DRE =
1084 Uses.push_back(DRE);
1087 return std::move(Uses);
1093class DecrementGadget :
public WarningGadget {
1094 static constexpr const char *
const OpTag =
"op";
1099 : WarningGadget(
Kind::Decrement),
1102 static bool classof(
const Gadget *G) {
1103 return G->getKind() == Kind::Decrement;
1106 static Matcher matcher() {
1114 bool IsRelatedToDecl,
1120 DeclUseList getClaimedVarUseSites()
const override {
1121 if (
const auto *DRE =
1132class ArraySubscriptGadget :
public WarningGadget {
1133 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1138 : WarningGadget(
Kind::ArraySubscript),
1141 static bool classof(
const Gadget *G) {
1142 return G->getKind() == Kind::ArraySubscript;
1145 static Matcher matcher() {
1148 hasBase(ignoringParenImpCasts(
1151 isSafeArraySubscript(),
1155 ))).bind(ArraySubscrTag));
1160 bool IsRelatedToDecl,
1166 DeclUseList getClaimedVarUseSites()
const override {
1167 if (
const auto *DRE =
1180class PointerArithmeticGadget :
public WarningGadget {
1181 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1182 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1188 : WarningGadget(
Kind::PointerArithmetic),
1190 Ptr(Result.
Nodes.getNodeAs<
Expr>(PointerArithmeticPointerTag)) {}
1192 static bool classof(
const Gadget *G) {
1193 return G->getKind() == Kind::PointerArithmetic;
1196 static Matcher matcher() {
1197 auto HasIntegerType =
anyOf(hasType(isInteger()), hasType(
enumType()));
1199 allOf(hasOperatorName(
"+"),
1201 hasLHS(HasIntegerType));
1203 allOf(
anyOf(hasOperatorName(
"+"), hasOperatorName(
"-"),
1204 hasOperatorName(
"+="), hasOperatorName(
"-=")),
1206 hasRHS(HasIntegerType));
1209 .bind(PointerArithmeticTag));
1213 bool IsRelatedToDecl,
1219 DeclUseList getClaimedVarUseSites()
const override {
1230class SpanTwoParamConstructorGadget :
public WarningGadget {
1231 static constexpr const char *
const SpanTwoParamConstructorTag =
1232 "spanTwoParamConstructor";
1237 : WarningGadget(
Kind::SpanTwoParamConstructor),
1239 SpanTwoParamConstructorTag)) {}
1241 static bool classof(
const Gadget *G) {
1242 return G->getKind() == Kind::SpanTwoParamConstructor;
1245 static Matcher matcher() {
1248 parameterCountIs(2)));
1251 unless(isSafeSpanTwoParamConstruct()))
1252 .bind(SpanTwoParamConstructorTag));
1256 return stmt(
unless(ignoreUnsafeBufferInContainer(Handler)), matcher());
1260 bool IsRelatedToDecl,
1266 DeclUseList getClaimedVarUseSites()
const override {
1269 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->
getArg(0))) {
1270 if (isa<VarDecl>(DRE->
getDecl()))
1281class PointerInitGadget :
public FixableGadget {
1283 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1284 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1290 : FixableGadget(
Kind::PointerInit),
1291 PtrInitLHS(Result.
Nodes.getNodeAs<
VarDecl>(PointerInitLHSTag)),
1294 static bool classof(
const Gadget *G) {
1295 return G->getKind() == Kind::PointerInit;
1298 static Matcher matcher() {
1299 auto PtrInitStmt =
declStmt(hasSingleDecl(
1300 varDecl(hasInitializer(ignoringImpCasts(
1302 .bind(PointerInitRHSTag))))
1303 .bind(PointerInitLHSTag)));
1305 return stmt(PtrInitStmt);
1308 virtual std::optional<FixItList>
1314 virtual DeclUseList getClaimedVarUseSites()
const override {
1315 return DeclUseList{PtrInitRHS};
1318 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1319 getStrategyImplications()
const override {
1320 return std::make_pair(PtrInitLHS, cast<VarDecl>(PtrInitRHS->
getDecl()));
1329class PtrToPtrAssignmentGadget :
public FixableGadget {
1331 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1332 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1338 : FixableGadget(
Kind::PtrToPtrAssignment),
1342 static bool classof(
const Gadget *G) {
1343 return G->getKind() == Kind::PtrToPtrAssignment;
1346 static Matcher matcher() {
1348 allOf(hasOperatorName(
"="),
1349 hasRHS(ignoringParenImpCasts(
1351 .bind(PointerAssignRHSTag))),
1353 .bind(PointerAssignLHSTag))));
1358 virtual std::optional<FixItList>
1362 virtual DeclUseList getClaimedVarUseSites()
const override {
1363 return DeclUseList{PtrLHS, PtrRHS};
1366 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1367 getStrategyImplications()
const override {
1368 return std::make_pair(cast<VarDecl>(PtrLHS->
getDecl()),
1369 cast<VarDecl>(PtrRHS->
getDecl()));
1378class CArrayToPtrAssignmentGadget :
public FixableGadget {
1380 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1381 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1387 : FixableGadget(
Kind::CArrayToPtrAssignment),
1391 static bool classof(
const Gadget *G) {
1392 return G->getKind() == Kind::CArrayToPtrAssignment;
1395 static Matcher matcher() {
1397 allOf(hasOperatorName(
"="),
1398 hasRHS(ignoringParenImpCasts(
1400 toSupportedVariable())
1401 .bind(PointerAssignRHSTag))),
1403 .bind(PointerAssignLHSTag))));
1408 virtual std::optional<FixItList>
1412 virtual DeclUseList getClaimedVarUseSites()
const override {
1413 return DeclUseList{PtrLHS, PtrRHS};
1416 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1417 getStrategyImplications()
const override {
1424class UnsafeBufferUsageAttrGadget :
public WarningGadget {
1425 constexpr static const char *
const OpTag =
"attr_expr";
1430 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
1431 Op(Result.
Nodes.getNodeAs<
Expr>(OpTag)) {}
1433 static bool classof(
const Gadget *G) {
1434 return G->getKind() == Kind::UnsafeBufferUsageAttr;
1437 static Matcher matcher() {
1438 auto HasUnsafeFieldDecl =
1441 auto HasUnsafeFnDecl =
1445 memberExpr(HasUnsafeFieldDecl).bind(OpTag)));
1449 bool IsRelatedToDecl,
1455 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1461class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
1462 constexpr static const char *
const OpTag =
"cxx_construct_expr";
1467 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
1470 static bool classof(
const Gadget *G) {
1471 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
1474 static Matcher matcher() {
1475 auto HasUnsafeCtorDecl =
1478 auto HasTwoParamSpanCtorDecl = SpanTwoParamConstructorGadget::matcher();
1485 bool IsRelatedToDecl,
1491 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1498class DataInvocationGadget :
public WarningGadget {
1499 constexpr static const char *
const OpTag =
"data_invocation_expr";
1504 : WarningGadget(
Kind::DataInvocation),
1507 static bool classof(
const Gadget *G) {
1508 return G->getKind() == Kind::DataInvocation;
1511 static Matcher matcher() {
1523 bool IsRelatedToDecl,
1529 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1532class UnsafeLibcFunctionCallGadget :
public WarningGadget {
1534 const Expr *UnsafeArg =
nullptr;
1535 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
1537 constexpr static const char *
const UnsafeSprintfTag =
1538 "UnsafeLibcFunctionCall_sprintf";
1539 constexpr static const char *
const UnsafeSizedByTag =
1540 "UnsafeLibcFunctionCall_sized_by";
1541 constexpr static const char *
const UnsafeStringTag =
1542 "UnsafeLibcFunctionCall_string";
1543 constexpr static const char *
const UnsafeVaListTag =
1544 "UnsafeLibcFunctionCall_va_list";
1556 } WarnedFunKind = OTHERS;
1560 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
1562 if (Result.Nodes.getNodeAs<
Decl>(UnsafeSprintfTag))
1563 WarnedFunKind = SPRINTF;
1564 else if (
auto *
E = Result.Nodes.getNodeAs<
Expr>(UnsafeStringTag)) {
1565 WarnedFunKind = STRING;
1567 }
else if (Result.Nodes.getNodeAs<
CallExpr>(UnsafeSizedByTag)) {
1568 WarnedFunKind = SIZED_BY;
1569 UnsafeArg =
Call->getArg(0);
1570 }
else if (Result.Nodes.getNodeAs<
Decl>(UnsafeVaListTag))
1571 WarnedFunKind = VA_LIST;
1575 return stmt(
unless(ignoreUnsafeLibcCall(Handler)),
1581 functionDecl(libc_func_matchers::isPredefinedUnsafeLibcFunc()),
1585 functionDecl(libc_func_matchers::isUnsafeVaListPrintfFunc())
1586 .bind(UnsafeVaListTag),
1589 functionDecl(libc_func_matchers::isUnsafeSprintfFunc())
1590 .bind(UnsafeSprintfTag)))),
1602 libc_func_matchers::hasUnsafeSnprintfBuffer())
1603 .bind(UnsafeSizedByTag),
1607 libc_func_matchers::hasUnsafePrintfStringArg(
1608 expr().bind(UnsafeStringTag)))));
1611 const Stmt *getBaseStmt()
const {
return Call; }
1616 bool IsRelatedToDecl,
1621 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1627class ULCArraySubscriptGadget :
public FixableGadget {
1629 static constexpr const char *
const ULCArraySubscriptTag =
1630 "ArraySubscriptUnderULC";
1635 : FixableGadget(
Kind::ULCArraySubscript),
1637 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
1640 static bool classof(
const Gadget *G) {
1641 return G->getKind() == Kind::ULCArraySubscript;
1644 static Matcher matcher() {
1646 auto BaseIsArrayOrPtrDRE = hasBase(
1647 ignoringParenImpCasts(
declRefExpr(ArrayOrPtr, toSupportedVariable())));
1654 virtual std::optional<FixItList>
1658 virtual DeclUseList getClaimedVarUseSites()
const override {
1659 if (
const auto *DRE =
1660 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts())) {
1670class UPCStandalonePointerGadget :
public FixableGadget {
1672 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
1677 : FixableGadget(
Kind::UPCStandalonePointer),
1679 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
1682 static bool classof(
const Gadget *G) {
1683 return G->getKind() == Kind::UPCStandalonePointer;
1686 static Matcher matcher() {
1688 auto target =
expr(ignoringParenImpCasts(
1690 .bind(DeclRefExprTag)));
1694 virtual std::optional<FixItList>
1698 virtual DeclUseList getClaimedVarUseSites()
const override {
return {
Node}; }
1701class PointerDereferenceGadget :
public FixableGadget {
1702 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
1703 static constexpr const char *
const OperatorTag =
"op";
1710 : FixableGadget(
Kind::PointerDereference),
1715 static bool classof(
const Gadget *G) {
1716 return G->getKind() == Kind::PointerDereference;
1719 static Matcher matcher() {
1722 hasOperatorName(
"*"),
1723 has(
expr(ignoringParenImpCasts(
1724 declRefExpr(toSupportedVariable()).bind(BaseDeclRefExprTag)))))
1730 DeclUseList getClaimedVarUseSites()
const override {
1731 return {BaseDeclRefExpr};
1734 virtual std::optional<FixItList>
1742class UPCAddressofArraySubscriptGadget :
public FixableGadget {
1744 static constexpr const char *
const UPCAddressofArraySubscriptTag =
1745 "AddressofArraySubscriptUnderUPC";
1750 : FixableGadget(
Kind::ULCArraySubscript),
1752 UPCAddressofArraySubscriptTag)) {
1753 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
1756 static bool classof(
const Gadget *G) {
1757 return G->getKind() == Kind::UPCAddressofArraySubscript;
1760 static Matcher matcher() {
1763 hasOperatorName(
"&"),
1765 ignoringParenImpCasts(
declRefExpr(toSupportedVariable()))))))
1766 .bind(UPCAddressofArraySubscriptTag)))));
1769 virtual std::optional<FixItList>
1773 virtual DeclUseList getClaimedVarUseSites()
const override {
1774 const auto *ArraySubst = cast<ArraySubscriptExpr>(
Node->getSubExpr());
1776 cast<DeclRefExpr>(ArraySubst->getBase()->IgnoreParenImpCasts());
1786class DeclUseTracker {
1787 using UseSetTy = SmallSet<const DeclRefExpr *, 16>;
1788 using DefMapTy = DenseMap<const VarDecl *, const DeclStmt *>;
1791 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
1795 DeclUseTracker() =
default;
1796 DeclUseTracker(
const DeclUseTracker &) =
delete;
1797 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
1798 DeclUseTracker(DeclUseTracker &&) =
default;
1799 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
1802 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
1806 assert(Uses->count(DRE) &&
1807 "DRE not found or claimed by multiple matchers!");
1812 bool hasUnclaimedUses(
const VarDecl *VD)
const {
1814 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
1819 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
1821 for (
auto use : *Uses) {
1823 ReturnSet.insert(use);
1829 void discoverDecl(
const DeclStmt *DS) {
1831 if (
const auto *VD = dyn_cast<VarDecl>(
D)) {
1843 return Defs.lookup(VD);
1852 static constexpr const char *
const UPCPreIncrementTag =
1853 "PointerPreIncrementUnderUPC";
1858 : FixableGadget(Kind::UPCPreIncrement),
1860 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
1864 return G->getKind() == Kind::UPCPreIncrement;
1874 hasUnaryOperand(
declRefExpr(toSupportedVariable())))
1875 .bind(UPCPreIncrementTag)))));
1878 virtual std::optional<FixItList>
1883 return {dyn_cast<DeclRefExpr>(
Node->getSubExpr())};
1891 static constexpr const char *
const UUCAddAssignTag =
1892 "PointerAddAssignUnderUUC";
1893 static constexpr const char *
const OffsetTag =
"Offset";
1896 const Expr *Offset =
nullptr;
1900 : FixableGadget(Kind::UUCAddAssign),
1902 Offset(Result.
Nodes.getNodeAs<
Expr>(OffsetTag)) {
1903 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
1907 return G->getKind() == Kind::UUCAddAssign;
1917 toSupportedVariable())),
1918 hasRHS(
expr().bind(OffsetTag)))
1919 .bind(UUCAddAssignTag)))));
1923 virtual std::optional<FixItList>
1928 return {dyn_cast<DeclRefExpr>(
Node->getLHS())};
1935 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
1936 static constexpr const char *
const DerefOpTag =
"DerefOp";
1937 static constexpr const char *
const AddOpTag =
"AddOp";
1938 static constexpr const char *
const OffsetTag =
"Offset";
1947 : FixableGadget(Kind::DerefSimplePtrArithFixable),
1957 ignoringImpCasts(
declRefExpr(toSupportedVariable()).
1958 bind(BaseDeclRefExprTag)));
1959 auto PlusOverPtrAndInteger =
expr(
anyOf(
1967 hasOperatorName(
"*"),
1968 hasUnaryOperand(ignoringParens(PlusOverPtrAndInteger)))
1973 virtual std::optional<FixItList>
1980 return {BaseDeclRefExpr};
1987 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
1988 WarningGadgetList &WarningGadgets,
1989 DeclUseTracker &Tracker) {
1992 GadgetFinderCallback(FixableGadgetList &FixableGadgets,
1993 WarningGadgetList &WarningGadgets,
1994 DeclUseTracker &Tracker)
1995 : FixableGadgets(FixableGadgets), WarningGadgets(WarningGadgets),
2004 [[maybe_unused]]
int numFound = 0;
2005#define NEXT ++numFound
2008 if (
const auto *DRE = Result.Nodes.getNodeAs<
DeclRefExpr>(
"any_dre")) {
2009 Tracker.discoverUse(DRE);
2013 if (
const auto *DS = Result.Nodes.getNodeAs<
DeclStmt>(
"any_ds")) {
2014 Tracker.discoverDecl(DS);
2021#define FIXABLE_GADGET(name) \
2022 if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
2023 FixableGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2026#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2027#define WARNING_GADGET(name) \
2028 if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
2029 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2032#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2034 assert(numFound >= 1 &&
"Gadgets not found in match result!");
2035 assert(numFound <= 1 &&
"Conflicting bind tags in gadgets!");
2038 FixableGadgetList &FixableGadgets;
2039 WarningGadgetList &WarningGadgets;
2040 DeclUseTracker &Tracker;
2044 GadgetFinderCallback CB{FixableGadgets, WarningGadgets, Tracker};
2049 forEachDescendantEvaluatedStmt(
stmt(
anyOf(
2052 allOf(x ## Gadget::matcher().bind(#x), \
2053 notInSafeBufferOptOut(&Handler)),
2055 allOf(x ## Gadget::matcher(&Handler).bind(#x), \
2056 notInSafeBufferOptOut(&Handler)),
2057#include
"clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2066 if (EmitSuggestions) {
2072 x ## Gadget::matcher().bind(#x),
2073#include
"clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2095 return N1->getBeginLoc().getRawEncoding() <
2096 N2->getBeginLoc().getRawEncoding();
2101 std::map<const VarDecl *, std::set<const WarningGadget *>,
2115 for (
auto &G : AllUnsafeOperations) {
2116 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
2118 bool AssociatedWithVarDecl =
false;
2119 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
2120 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2121 result.
byVar[VD].insert(G.get());
2122 AssociatedWithVarDecl =
true;
2126 if (!AssociatedWithVarDecl) {
2127 result.
noVar.push_back(G.get());
2135 std::map<const VarDecl *, std::set<const FixableGadget *>,
2145 for (
auto &F : AllFixableOperations) {
2146 DeclUseList DREs = F->getClaimedVarUseSites();
2149 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2150 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
2154 return FixablesForUnsafeVars;
2161 std::vector<const FixItHint *> All;
2165 std::sort(All.begin(), All.end(),
2167 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
2168 H2->RemoveRange.getBegin());
2176 Hint->RemoveRange.getBegin())) {
2188std::optional<FixItList>
2189PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2190 const auto *LeftVD = cast<VarDecl>(PtrLHS->
getDecl());
2191 const auto *RightVD = cast<VarDecl>(PtrRHS->
getDecl());
2192 switch (S.lookup(LeftVD)) {
2193 case FixitStrategy::Kind::Span:
2194 if (S.lookup(RightVD) == FixitStrategy::Kind::Span)
2196 return std::nullopt;
2197 case FixitStrategy::Kind::Wontfix:
2198 return std::nullopt;
2199 case FixitStrategy::Kind::Iterator:
2200 case FixitStrategy::Kind::Array:
2201 return std::nullopt;
2202 case FixitStrategy::Kind::Vector:
2203 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2205 return std::nullopt;
2212std::optional<FixItList>
2213CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2214 const auto *LeftVD = cast<VarDecl>(PtrLHS->
getDecl());
2215 const auto *RightVD = cast<VarDecl>(PtrRHS->
getDecl());
2232 if (S.lookup(LeftVD) == FixitStrategy::Kind::Span) {
2233 if (S.lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
2236 }
else if (S.lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
2237 if (S.lookup(RightVD) == FixitStrategy::Kind::Array) {
2241 return std::nullopt;
2244std::optional<FixItList>
2246 const auto *LeftVD = PtrInitLHS;
2247 const auto *RightVD = cast<VarDecl>(PtrInitRHS->
getDecl());
2248 switch (S.lookup(LeftVD)) {
2249 case FixitStrategy::Kind::Span:
2250 if (S.lookup(RightVD) == FixitStrategy::Kind::Span)
2252 return std::nullopt;
2253 case FixitStrategy::Kind::Wontfix:
2254 return std::nullopt;
2255 case FixitStrategy::Kind::Iterator:
2256 case FixitStrategy::Kind::Array:
2257 return std::nullopt;
2258 case FixitStrategy::Kind::Vector:
2259 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2261 return std::nullopt;
2267 if (ConstVal->isNegative())
2274std::optional<FixItList>
2275ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2276 if (
const auto *DRE =
2277 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts()))
2278 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2279 switch (S.lookup(VD)) {
2280 case FixitStrategy::Kind::Span: {
2287 return std::nullopt;
2291 case FixitStrategy::Kind::Array:
2293 case FixitStrategy::Kind::Wontfix:
2294 case FixitStrategy::Kind::Iterator:
2295 case FixitStrategy::Kind::Vector:
2296 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2299 return std::nullopt;
2302static std::optional<FixItList>
2305std::optional<FixItList>
2306UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2307 auto DREs = getClaimedVarUseSites();
2308 const auto *VD = cast<VarDecl>(DREs.front()->getDecl());
2310 switch (S.lookup(VD)) {
2311 case FixitStrategy::Kind::Span:
2313 case FixitStrategy::Kind::Wontfix:
2314 case FixitStrategy::Kind::Iterator:
2315 case FixitStrategy::Kind::Array:
2316 return std::nullopt;
2317 case FixitStrategy::Kind::Vector:
2318 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2320 return std::nullopt;
2325 static const char *
const EOL =
"\n";
2332 std::string
s = std::string(
"<# ");
2333 s += HintTextToUser;
2339template <
typename NodeTy>
2340static std::optional<SourceLocation>
2349 return std::nullopt;
2353template <
typename NodeTy>
2361 return std::nullopt;
2368 std::optional<SourceLocation> LastCharLoc =
getPastLoc(
E,
SM, LangOpts);
2375 return std::nullopt;
2388 return std::nullopt;
2400static std::optional<StringRef>
2409 return std::nullopt;
2410 return getRangeText({ParmIdentBeginLoc, ParmIdentEndLoc},
SM, LangOpts);
2423 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
2424 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
2425 VD->getBeginLoc())) &&
2426 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
2427 At->getRange().getBegin()));
2431 AttrRangeOverlapping;
2455static std::optional<std::string>
2458 std::optional<Qualifiers> *QualifiersToAppend) {
2463 "Expecting a VarDecl of type of pointer to object type");
2472 case TypeLoc::ConstantArray:
2473 case TypeLoc::IncompleteArray:
2474 case TypeLoc::VariableArray:
2475 case TypeLoc::DependentSizedArray:
2476 case TypeLoc::Decayed:
2477 assert(isa<ParmVarDecl>(VD) &&
"An array type shall not be treated as a "
2478 "pointer type unless it decays.");
2481 case TypeLoc::Pointer:
2485 return std::nullopt;
2490 return std::nullopt;
2498 return std::nullopt;
2505 if (!PteEndOfTokenLoc.
isValid())
2508 return std::nullopt;
2509 if (!
SM.isBeforeInTranslationUnit(PteEndOfTokenLoc, IdentLoc)) {
2516 return std::nullopt;
2551 std::optional<Qualifiers> Quals = std::nullopt) {
2552 const char *
const SpanOpen =
"std::span<";
2555 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
2556 return SpanOpen + EltTyText.str() +
'>';
2559std::optional<FixItList>
2561 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->
getDecl());
2563 if (VD &&
s.lookup(VD) == FixitStrategy::Kind::Span) {
2567 if (ConstVal->isNegative())
2568 return std::nullopt;
2596 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
2598 return std::nullopt;
2603 std::optional<SourceLocation> AddOpLocation =
2605 std::optional<SourceLocation> DerefOpLocation =
2608 if (!AddOpLocation || !DerefOpLocation)
2609 return std::nullopt;
2619 return std::nullopt;
2622std::optional<FixItList>
2623PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
2625 switch (S.lookup(VD)) {
2626 case FixitStrategy::Kind::Span: {
2634 if (
auto LocPastOperand =
2641 case FixitStrategy::Kind::Iterator:
2642 case FixitStrategy::Kind::Array:
2643 return std::nullopt;
2644 case FixitStrategy::Kind::Vector:
2645 llvm_unreachable(
"FixitStrategy not implemented yet!");
2646 case FixitStrategy::Kind::Wontfix:
2647 llvm_unreachable(
"Invalid strategy!");
2650 return std::nullopt;
2657 std::optional<SourceLocation> EndOfOperand =
2663 return std::nullopt;
2668std::optional<FixItList>
2669UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
2670 const auto VD = cast<VarDecl>(
Node->getDecl());
2671 switch (S.lookup(VD)) {
2672 case FixitStrategy::Kind::Array:
2673 case FixitStrategy::Kind::Span: {
2678 case FixitStrategy::Kind::Wontfix:
2679 case FixitStrategy::Kind::Iterator:
2680 return std::nullopt;
2681 case FixitStrategy::Kind::Vector:
2682 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2685 return std::nullopt;
2690static std::optional<FixItList>
2692 const auto *ArraySub = cast<ArraySubscriptExpr>(
Node->getSubExpr());
2693 const auto *DRE = cast<DeclRefExpr>(ArraySub->getBase()->IgnoreImpCasts());
2697 const Expr *Idx = ArraySub->getIdx();
2700 std::stringstream SS;
2701 bool IdxIsLitZero =
false;
2704 if ((*ICE).isZero())
2705 IdxIsLitZero =
true;
2706 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
2708 return std::nullopt;
2712 SS << (*DreString).str() <<
".data()";
2714 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
2716 return std::nullopt;
2718 SS <<
"&" << (*DreString).str() <<
".data()"
2719 <<
"[" << (*IndexString).str() <<
"]";
2725std::optional<FixItList>
2729 if (DREs.size() != 1)
2730 return std::nullopt;
2732 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
2733 if (S.lookup(VD) == FixitStrategy::Kind::Span) {
2737 StringRef varName = VD->
getName();
2741 return std::nullopt;
2746 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
2750 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
2752 if (!AddAssignLocation)
2753 return std::nullopt;
2764 return std::nullopt;
2767std::optional<FixItList>
2771 if (DREs.size() != 1)
2772 return std::nullopt;
2774 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
2775 if (S.lookup(VD) == FixitStrategy::Kind::Span) {
2777 std::stringstream SS;
2778 StringRef varName = VD->
getName();
2782 SS <<
"(" << varName.data() <<
" = " << varName.data()
2783 <<
".subspan(1)).data()";
2784 std::optional<SourceLocation> PreIncLocation =
2786 if (!PreIncLocation)
2787 return std::nullopt;
2794 return std::nullopt;
2812static std::optional<FixItList>
2814 const StringRef UserFillPlaceHolder) {
2822 if (
Init->isNullPointerConstant(
2827 NPC_ValueDependentIsNotNull)) {
2828 std::optional<SourceLocation> InitLocation =
2831 return std::nullopt;
2839 std::string ExtentText = UserFillPlaceHolder.data();
2840 StringRef One =
"1";
2845 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
2850 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
2851 if (!Ext->HasSideEffects(Ctx)) {
2852 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
2854 return std::nullopt;
2855 ExtentText = *ExtentString;
2857 }
else if (!CxxNew->isArray())
2869 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
2870 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
2871 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
2878 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
2881 return std::nullopt;
2883 StrBuffer.append(
", ");
2884 StrBuffer.append(ExtentText);
2885 StrBuffer.append(
"}");
2891#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
2892 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
2893 "failed to produce fixit for declaration '" + \
2894 (D)->getNameAsString() + "'" + (Msg))
2896#define DEBUG_NOTE_DECL_FAIL(D, Msg)
2902static std::optional<std::string>
2906 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
2911 return std::nullopt;
2913 std::string SpanTyText =
"std::span<";
2915 SpanTyText.append(*PteTyText);
2917 if (PteTyQualifiers) {
2918 SpanTyText.append(
" ");
2919 SpanTyText.append(PteTyQualifiers->getAsString());
2921 SpanTyText.append(
">");
2940 const StringRef UserFillPlaceHolder,
2954 std::stringstream SS;
2959 std::optional<FixItList> InitFixIts =
2963 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
2964 std::make_move_iterator(InitFixIts->end()));
2971 if (!EndLocForReplacement.
isValid()) {
3021static std::optional<FixItList>
3027 return std::nullopt;
3032 std::vector<std::string> NewTysTexts(NumParms);
3033 std::vector<bool> ParmsMask(NumParms,
false);
3034 bool AtLeastOneParmToFix =
false;
3036 for (
unsigned i = 0; i < NumParms; i++) {
3039 if (S.lookup(PVD) == FixitStrategy::Kind::Wontfix)
3041 if (S.lookup(PVD) != FixitStrategy::Kind::Span)
3043 return std::nullopt;
3045 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3046 std::optional<std::string> PteTyText =
3051 return std::nullopt;
3055 ParmsMask[i] =
true;
3056 AtLeastOneParmToFix =
true;
3058 if (!AtLeastOneParmToFix)
3065 const auto NewOverloadSignatureCreator =
3066 [&
SM, &LangOpts, &NewTysTexts,
3067 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3068 std::stringstream SS;
3076 SS << Prefix->str();
3078 return std::nullopt;
3082 for (
unsigned i = 0; i < NumParms; i++) {
3090 SS << NewTysTexts[i];
3093 SS <<
' ' << II->
getName().str();
3094 }
else if (
auto ParmTypeText =
3098 SS << ParmTypeText->str();
3100 return std::nullopt;
3101 if (i != NumParms - 1)
3110 const auto OldOverloadDefCreator =
3111 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3112 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3113 std::stringstream SS;
3121 << FDPrefix->str() <<
"{";
3123 return std::nullopt;
3126 SS <<
"return " << FunQualName->str() <<
"(";
3128 return std::nullopt;
3132 for (
unsigned i = 0; i < NumParms; i++) {
3141 return std::nullopt;
3148 if (i != NumParms - 1)
3159 std::optional<SourceLocation>
Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3163 if (FReDecl->isThisDeclarationADefinition()) {
3164 assert(FReDecl == FD &&
"inconsistent function definition");
3167 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3173 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3176 FReDecl->getBeginLoc(),
" ")));
3179 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3201 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3217 std::stringstream SS;
3220 if (PteTyQualifiers)
3229 SS <<
' ' << PVDNameText->str();
3235 const DeclUseTracker &Tracker,
3238 const DeclStmt *DS = Tracker.lookupDecl(VD);
3241 " : variables declared this way not implemented yet");
3265 const QualType &ArrayEltT = CAT->getElementType();
3266 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
3275 auto MaybeElemTypeTxt =
3278 if (!MaybeElemTypeTxt)
3280 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
3285 while (NextTok && !NextTok->is(tok::l_square) &&
3298 if (!MaybeArraySizeTxt)
3300 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
3301 if (ArraySizeTxt.empty()) {
3312 std::optional<StringRef> IdentText =
3321 raw_svector_ostream OS(Replacement);
3322 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
3323 << IdentText->str();
3333 const DeclUseTracker &Tracker,
3336 const DeclStmt *DS = Tracker.lookupDecl(VD);
3337 assert(DS &&
"Fixing non-local variables not implemented yet!");
3356 const DeclUseTracker &Tracker,
ASTContext &Ctx,
3358 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
3359 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
3360 if (!FD || FD !=
D) {
3371 if (FD->isMain() || FD->isConstexpr() ||
3372 FD->getTemplatedKind() != FunctionDecl::TemplatedKind::TK_NonTemplate ||
3375 isa<CXXMethodDecl>(FD) ||
3377 (FD->hasBody() && isa<CXXTryStmt>(FD->getBody())) ||
3378 FD->isOverloadedOperator()) {
3385 case FixitStrategy::Kind::Span: {
3387 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
3396 case FixitStrategy::Kind::Array: {
3403 case FixitStrategy::Kind::Iterator:
3404 case FixitStrategy::Kind::Vector:
3405 llvm_unreachable(
"FixitStrategy not implemented yet!");
3406 case FixitStrategy::Kind::Wontfix:
3407 llvm_unreachable(
"Invalid strategy!");
3409 llvm_unreachable(
"Unknown strategy!");
3417 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
3428 return isa<ParmVarDecl>(VD) &&
3436 std::map<const VarDecl *, FixItList> &FixItsForVariable,
3441 for (
const auto &[VD, Ignore] : FixItsForVariable) {
3443 if (llvm::any_of(Grp,
3444 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
3445 return !FixItsForVariable.count(GrpMember);
3450 ToErase.push_back(
Member);
3453 for (
auto *VarToErase : ToErase)
3454 FixItsForVariable.erase(VarToErase);
3465 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
3469 FixItList FixItsSharedByParms{};
3471 std::optional<FixItList> OverloadFixes =
3474 if (OverloadFixes) {
3475 FixItsSharedByParms.append(*OverloadFixes);
3481 FixItsForVariable.erase(
Member);
3483 return FixItsSharedByParms;
3487static std::map<const VarDecl *, FixItList>
3496 std::map<const VarDecl *, FixItList> FixItsForVariable;
3501 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
3502 FixItsForVariable[VD] =
3503 fixVariable(VD, S.lookup(VD),
D, Tracker, Ctx, Handler);
3506 if (FixItsForVariable[VD].empty()) {
3507 FixItsForVariable.erase(VD);
3510 for (
const auto &F : Fixables) {
3511 std::optional<FixItList> Fixits = F->getFixits(S);
3514 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
3515 Fixits->begin(), Fixits->end());
3520 VD, F->getSourceLoc(),
3521 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
3524 FixItsForVariable.erase(VD);
3543 FixItList FixItsSharedByParms{};
3545 if (
auto *FD = dyn_cast<FunctionDecl>(
D))
3547 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
3551 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
3554 for (
auto &[Var, Ignore] : FixItsForVariable) {
3555 bool AnyParm =
false;
3556 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
3558 for (
const VarDecl *GrpMate : VarGroupForVD) {
3561 if (FixItsForVariable.count(GrpMate))
3562 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
3566 assert(!FixItsSharedByParms.empty() &&
3567 "Should not try to fix a parameter that does not belong to a "
3569 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
3576 for (
auto Iter = FinalFixItsForVariable.begin();
3577 Iter != FinalFixItsForVariable.end();)
3580 Iter = FinalFixItsForVariable.erase(
Iter);
3583 return FinalFixItsForVariable;
3586template <
typename VarDeclIterTy>
3590 for (
const VarDecl *VD : UnsafeVars) {
3592 S.set(VD, FixitStrategy::Kind::Array);
3594 S.set(VD, FixitStrategy::Kind::Span);
3601 const std::vector<VarGrpTy> Groups;
3602 const std::map<const VarDecl *, unsigned> &VarGrpMap;
3603 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
3607 const std::vector<VarGrpTy> &Groups,
3608 const std::map<const VarDecl *, unsigned> &VarGrpMap,
3609 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
3610 : Groups(Groups), VarGrpMap(VarGrpMap),
3611 GrpsUnionForParms(GrpsUnionForParms) {}
3614 if (GrpsUnionForParms.contains(Var)) {
3617 return GrpsUnionForParms.getArrayRef();
3622 auto It = VarGrpMap.find(Var);
3624 if (It == VarGrpMap.end())
3626 return Groups[It->second];
3630 return GrpsUnionForParms.getArrayRef();
3635 WarningGadgetList WarningGadgets, DeclUseTracker Tracker,
3637 if (!EmitSuggestions) {
3641 for (
const auto &G : WarningGadgets) {
3642 G->handleUnsafeOperation(Handler,
false,
3648 assert(FixableGadgets.size() == 0 &&
3649 "Fixable gadgets found but suggestions not requested!");
3655 if (!WarningGadgets.empty()) {
3659 for (
const auto &G : FixableGadgets) {
3660 for (
const auto *DRE : G->getClaimedVarUseSites()) {
3661 Tracker.claimUse(DRE);
3677 if (WarningGadgets.empty())
3685 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
3688 for (
auto it = FixablesForAllVars.
byVar.cbegin();
3689 it != FixablesForAllVars.
byVar.cend();) {
3691 if ((!it->first->isLocalVarDecl() && !isa<ParmVarDecl>(it->first))) {
3694 (
"failed to produce fixit for '" +
3695 it->first->getNameAsString() +
3696 "' : neither local nor a parameter"));
3698 it = FixablesForAllVars.
byVar.erase(it);
3699 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
3702 (
"failed to produce fixit for '" +
3703 it->first->getNameAsString() +
3704 "' : has a reference type"));
3706 it = FixablesForAllVars.
byVar.erase(it);
3707 }
else if (Tracker.hasUnclaimedUses(it->first)) {
3708 it = FixablesForAllVars.
byVar.erase(it);
3709 }
else if (it->first->isInitCapture()) {
3712 (
"failed to produce fixit for '" +
3713 it->first->getNameAsString() +
3714 "' : init capture"));
3716 it = FixablesForAllVars.
byVar.erase(it);
3723 for (
const auto &it : UnsafeOps.
byVar) {
3724 const VarDecl *
const UnsafeVD = it.first;
3725 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
3726 if (UnclaimedDREs.empty())
3730 std::string UnclaimedUseTrace =
3735 (
"failed to produce fixit for '" + UnfixedVDName +
3736 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
3737 UnclaimedUseTrace));
3743 using DepMapTy = DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
3744 DepMapTy DependenciesMap{};
3745 DepMapTy PtrAssignmentGraph{};
3747 for (
auto it : FixablesForAllVars.
byVar) {
3748 for (
const FixableGadget *fixable : it.second) {
3749 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
3750 fixable->getStrategyImplications();
3752 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
3753 PtrAssignmentGraph[Impl.first].insert(Impl.second);
3775 std::set<const VarDecl *> VisitedVarsDirected{};
3776 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
3777 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
3779 std::queue<const VarDecl *> QueueDirected{};
3780 QueueDirected.push(Var);
3781 while (!QueueDirected.empty()) {
3782 const VarDecl *CurrentVar = QueueDirected.front();
3783 QueueDirected.pop();
3784 VisitedVarsDirected.insert(CurrentVar);
3785 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
3786 for (
const VarDecl *Adj : AdjacentNodes) {
3787 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
3788 QueueDirected.push(Adj);
3790 DependenciesMap[Var].insert(Adj);
3791 DependenciesMap[Adj].insert(Var);
3798 std::vector<VarGrpTy> Groups;
3802 std::map<const VarDecl *, unsigned> VarGrpMap;
3804 llvm::SetVector<const VarDecl *>
3809 std::set<const VarDecl *> VisitedVars{};
3810 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
3811 if (VisitedVars.find(Var) == VisitedVars.end()) {
3812 VarGrpTy &VarGroup = Groups.emplace_back();
3813 std::queue<const VarDecl *> Queue{};
3816 while (!Queue.empty()) {
3817 const VarDecl *CurrentVar = Queue.front();
3819 VisitedVars.insert(CurrentVar);
3820 VarGroup.push_back(CurrentVar);
3821 auto AdjacentNodes = DependenciesMap[CurrentVar];
3822 for (
const VarDecl *Adj : AdjacentNodes) {
3823 if (VisitedVars.find(Adj) == VisitedVars.end()) {
3829 bool HasParm =
false;
3830 unsigned GrpIdx = Groups.size() - 1;
3832 for (
const VarDecl *
V : VarGroup) {
3833 VarGrpMap[
V] = GrpIdx;
3838 GrpsUnionForParms.insert(VarGroup.begin(), VarGroup.end());
3860 for (
auto I = FixablesForAllVars.
byVar.begin();
3861 I != FixablesForAllVars.
byVar.end();) {
3863 if (!VisitedVars.count((*I).first)) {
3865 I = FixablesForAllVars.
byVar.erase(I);
3873 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
3875 return FixablesForAllVars.
byVar.count(
V);
3879 if (isa<NamedDecl>(
D))
3882 FixItsForVariableGroup =
3884 Tracker, Handler, VarGrpMgr);
3886 for (
const auto &G : UnsafeOps.
noVar) {
3887 G->handleUnsafeOperation(Handler,
false,
3891 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
3892 auto FixItsIt = FixItsForVariableGroup.find(VD);
3894 FixItsIt != FixItsForVariableGroup.end()
3895 ? std::move(FixItsIt->second)
3898 for (
const auto &G : WarningGadgets) {
3899 G->handleUnsafeOperation(Handler,
true,
3907 bool EmitSuggestions) {
3916 if (
const auto *FD = dyn_cast<FunctionDecl>(
D)) {
3920 if (
const auto *MD = dyn_cast<CXXMethodDecl>(
D)) {
3921 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
3926 if (FReDecl->isExternC()) {
3929 EmitSuggestions =
false;
3934 Stmts.push_back(FD->getBody());
3936 if (
const auto *ID = dyn_cast<CXXConstructorDecl>(
D)) {
3938 Stmts.push_back(CI->getInit());
3941 }
else if (isa<BlockDecl>(
D) || isa<ObjCMethodDecl>(
D)) {
3945 assert(!Stmts.empty());
3947 FixableGadgetList FixableGadgets;
3948 WarningGadgetList WarningGadgets;
3949 DeclUseTracker Tracker;
3950 for (
Stmt *S : Stmts) {
3952 WarningGadgets, Tracker);
3954 applyGadgets(
D, std::move(FixableGadgets), std::move(WarningGadgets),
3955 std::move(Tracker), Handler, EmitSuggestions);
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 QualType getPointeeType(const MemRegion *R)
C Language Family Type Representation.
static std::string getUserFillPlaceHolder(StringRef HintTextToUser="placeholder")
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)
#define WARNING_OPTIONAL_GADGET(x)
static FixItList fixVarDeclWithArray(const VarDecl *D, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
void applyGadgets(const Decl *D, FixableGadgetList FixableGadgets, WarningGadgetList WarningGadgets, DeclUseTracker Tracker, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
#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)
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 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 void findGadgets(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, bool EmitSuggestions, FixableGadgetList &FixableGadgets, WarningGadgetList &WarningGadgets, DeclUseTracker &Tracker)
Scan the function and return a list of gadgets found with provided kits.
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)
__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.
QualType getFILEType() const
Retrieve the C FILE type.
const LangOptions & getLangOpts() const
const TargetInfo & getTargetInfo() 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++ base or member initializer.
A use of a default initializer in a constructor or in aggregate initialization.
Represents a static or instance method of a struct/union/class.
Represents a C++11 noexcept expression (C++ [expr.unary.noexcept]).
Represents a C++ struct/union/class.
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
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.
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.
bool isInStdNamespace() const
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.
Recursive AST visitor that supports extension via dynamic dispatch.
virtual bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
virtual bool TraverseStmt(Stmt *S)
Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...
bool ShouldVisitImplicitCode
Whether this visitor should recurse into implicit code, e.g.
bool ShouldVisitTemplateInstantiations
Whether this visitor should recurse into template instantiations.
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.
PointerType - C99 6.7.5.1 - Pointer Declarators.
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
bool isConstQualified() const
Determine whether this type is const-qualified.
std::string getAsString() const
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
Exposes information about the current target.
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
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
const T * castAs() const
Member-template castAs<specific type>.
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.
virtual void handleUnsafeLibcCall(const CallExpr *Call, unsigned PrintfInfo, ASTContext &Ctx, const Expr *UnsafeArg=nullptr)=0
Invoked when a call to an unsafe libc function 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 TraverseCXXNoexceptExpr(CXXNoexceptExpr *Node) override
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc Node) override
bool TraverseCXXDefaultInitExpr(CXXDefaultInitExpr *Node) override
bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) override
bool TraverseGenericSelectionExpr(GenericSelectionExpr *Node) override
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc Node) override
bool TraverseStmt(Stmt *Node) override
Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...
bool TraverseCXXTypeidExpr(CXXTypeidExpr *Node) override
MatchDescendantVisitor(const internal::DynTypedMatcher *Matcher, internal::ASTMatchFinder *Finder, internal::BoundNodesTreeBuilder *Builder, internal::ASTMatchFinder::BindKind Bind, const bool ignoreUnevaluatedContext)
bool TraverseDecl(Decl *Node) override
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
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.
static bool isNullTermPointer(const Expr *Ptr)
static bool hasUnsafeFormatOrSArg(const CallExpr *Call, const Expr *&UnsafeArg, const unsigned FmtArgIdx, ASTContext &Ctx, bool isKprintf=false)
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 internal::VariadicDynCastAllOfMatcher< Stmt, StringLiteral > stringLiteral
Matches string literals (also matches wide string literals).
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)
bool Call(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
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
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.
Wraps an identifier and optional source location for the identifier.
Contains all information for a given match.
StringRef matchLibcName(StringRef Name)
StringRef matchLibcNameOrBuiltinChk(StringRef Name)
StringRef matchName(StringRef FunName, bool isBuiltin)