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;
457 const Expr *IndexExpr =
Node.getIdx();
459 IndexExpr->
EvaluateAsInt(EVResult, Finder->getASTContext())) {
460 llvm::APSInt ArrIdx = EVResult.
Val.
getInt();
463 if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit)
470 return Node.getNumArgs() ==
Num;
473namespace libc_func_matchers {
489 StringRef
matchName(StringRef FunName,
bool isBuiltin) {
491 if (isBuiltin && FunName.starts_with(
"__builtin_"))
495 FunName.drop_front(10 ));
497 if (FunName.starts_with(
"__asan_"))
505 if (Name.starts_with(
"__") && Name.ends_with(
"_chk"))
507 Name.drop_front(2).drop_back(4) );
512 if (Name.ends_with(
"_s"))
513 return Name.drop_back(2 );
546 bool isKprintf =
false) {
547 class StringFormatStringHandler
551 const Expr *&UnsafeArg;
554 StringFormatStringHandler(
const CallExpr *
Call,
unsigned FmtArgIdx,
555 const Expr *&UnsafeArg)
556 :
Call(
Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg) {}
559 const char *startSpecifier,
560 unsigned specifierLen,
562 if (FS.getConversionSpecifier().getKind() ==
563 analyze_printf::PrintfConversionSpecifier::sArg) {
564 unsigned ArgIdx = FS.getPositionalArgIndex() + FmtArgIdx;
566 if (0 < ArgIdx && ArgIdx < Call->getNumArgs())
568 UnsafeArg =
Call->getArg(ArgIdx);
577 const Expr *Fmt =
Call->getArg(FmtArgIdx);
582 if (SL->getCharByteWidth() == 1)
583 FmtStr = SL->getString();
584 else if (
auto EvaledFmtStr = SL->tryEvaluateString(Ctx))
585 FmtStr = *EvaledFmtStr;
587 goto CHECK_UNSAFE_PTR;
589 StringFormatStringHandler Handler(
Call, FmtArgIdx, UnsafeArg);
592 Handler, FmtStr.begin(), FmtStr.end(), Ctx.
getLangOpts(),
600 llvm::make_range(
Call->arg_begin() + FmtArgIdx,
Call->arg_end()),
601 [&UnsafeArg](
const Expr *Arg) ->
bool {
602 if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg)) {
620 static std::unique_ptr<std::set<StringRef>> PredefinedNames =
nullptr;
621 if (!PredefinedNames)
623 std::make_unique<std::set<StringRef>, std::set<StringRef>>({
695 auto *II =
Node.getIdentifier();
701 II->getName(),
Node.getBuiltinID());
704 if (PredefinedNames->find(Name) != PredefinedNames->end())
707 std::string NameWCS = Name.str();
708 size_t WcsPos = NameWCS.find(
"wcs");
710 while (WcsPos != std::string::npos) {
711 NameWCS[WcsPos++] =
's';
712 NameWCS[WcsPos++] =
't';
713 NameWCS[WcsPos++] =
'r';
714 WcsPos = NameWCS.find(
"wcs", WcsPos);
716 if (PredefinedNames->find(NameWCS) != PredefinedNames->end())
720 return Name.ends_with(
"scanf");
727 auto *II =
Node.getIdentifier();
733 II->getName(),
Node.getBuiltinID());
735 if (!Name.ends_with(
"printf"))
737 return Name.starts_with(
"v");
743 auto *II =
Node.getIdentifier();
749 II->getName(),
Node.getBuiltinID());
751 if (!Name.ends_with(
"printf") ||
753 Name.starts_with(
"v"))
756 StringRef Prefix = Name.drop_back(6);
758 if (Prefix.ends_with(
"w"))
759 Prefix = Prefix.drop_back(1);
760 return Prefix ==
"s";
767 auto *II =
Node.getIdentifier();
773 II->getName(),
Node.getBuiltinID());
775 if (!Name.ends_with(
"printf") || Name.starts_with(
"v"))
778 StringRef Prefix = Name.drop_back(6);
780 if (Prefix.ends_with(
"w"))
781 Prefix = Prefix.drop_back(1);
783 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
791 clang::ast_matchers::internal::Matcher<Expr>,
792 UnsafeStringArgMatcher) {
796 assert(FD &&
"It should have been checked that FD is non-null.");
815 const Expr *UnsafeArg;
818 return UnsafeStringArgMatcher.matches(*UnsafeArg, Finder, Builder);
824 bool isKprintf =
false;
825 const Expr *UnsafeArg;
828 isKprintf = II->getName() ==
"kprintf";
830 return UnsafeStringArgMatcher.matches(*UnsafeArg, Finder, Builder);
840 const Expr *UnsafeArg;
843 return UnsafeStringArgMatcher.matches(*UnsafeArg, Finder, Builder);
849 for (
auto Arg :
Node.arguments())
851 if (UnsafeStringArgMatcher.matches(*Arg, Finder, Builder))
875 assert(FD &&
"It should have been checked that FD is non-null.");
886 const Expr *Buf =
Node.getArg(0), *Size =
Node.getArg(1);
889 !Size->getType()->isIntegerType())
893 static StringRef SizedObjs[] = {
"span",
"array",
"vector",
894 "basic_string_view",
"basic_string"};
896 Size = Size->IgnoreParenImpCasts();
897 if (
auto *MCEPtr = dyn_cast<CXXMemberCallExpr>(Buf))
898 if (
auto *MCESize = dyn_cast<CXXMemberCallExpr>(Size)) {
899 auto *DREOfPtr = dyn_cast<DeclRefExpr>(
900 MCEPtr->getImplicitObjectArgument()->IgnoreParenImpCasts());
901 auto *DREOfSize = dyn_cast<DeclRefExpr>(
902 MCESize->getImplicitObjectArgument()->IgnoreParenImpCasts());
904 if (!DREOfPtr || !DREOfSize)
906 if (DREOfPtr->getDecl() != DREOfSize->getDecl())
908 if (MCEPtr->getMethodDecl()->getName() !=
"data")
911 if (MCESize->getMethodDecl()->getName() ==
"size_bytes" ||
916 MCESize->getMethodDecl()->getName() ==
"size")
917 for (StringRef SizedObj : SizedObjs)
918 if (MCEPtr->getRecordDecl()->isInStdNamespace() &&
919 MCEPtr->getRecordDecl()->getCanonicalDecl()->getName() ==
933 if (Size->EvaluateAsConstantExpr(ER, Ctx)) {
936 return APSInt::compareValues(EVal,
APSInt(CAT->getSize(),
true)) != 0;
967#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
973 using Matcher =
decltype(
stmt());
975 Gadget(Kind K) : K(K) {}
980 StringRef getDebugName()
const {
985#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
987 llvm_unreachable(
"Unhandled Gadget::Kind enum");
991 virtual bool isWarningGadget()
const = 0;
999 virtual DeclUseList getClaimedVarUseSites()
const = 0;
1001 virtual ~Gadget() =
default;
1009class WarningGadget :
public Gadget {
1011 WarningGadget(Kind K) : Gadget(K) {}
1013 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1014 bool isWarningGadget() const final {
return true; }
1017 bool IsRelatedToDecl,
1025class FixableGadget :
public Gadget {
1027 FixableGadget(Kind K) : Gadget(K) {}
1029 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1030 bool isWarningGadget() const final {
return false; }
1035 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1036 return std::nullopt;
1045 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1046 getStrategyImplications()
const {
1047 return std::nullopt;
1051static auto toSupportedVariable() {
return to(
varDecl()); }
1053using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1054using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1058class IncrementGadget :
public WarningGadget {
1059 static constexpr const char *
const OpTag =
"op";
1064 : WarningGadget(
Kind::Increment),
1067 static bool classof(
const Gadget *G) {
1068 return G->getKind() == Kind::Increment;
1071 static Matcher matcher() {
1079 bool IsRelatedToDecl,
1085 DeclUseList getClaimedVarUseSites()
const override {
1087 if (
const auto *DRE =
1089 Uses.push_back(DRE);
1092 return std::move(Uses);
1098class DecrementGadget :
public WarningGadget {
1099 static constexpr const char *
const OpTag =
"op";
1104 : WarningGadget(
Kind::Decrement),
1107 static bool classof(
const Gadget *G) {
1108 return G->getKind() == Kind::Decrement;
1111 static Matcher matcher() {
1119 bool IsRelatedToDecl,
1125 DeclUseList getClaimedVarUseSites()
const override {
1126 if (
const auto *DRE =
1137class ArraySubscriptGadget :
public WarningGadget {
1138 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1143 : WarningGadget(
Kind::ArraySubscript),
1146 static bool classof(
const Gadget *G) {
1147 return G->getKind() == Kind::ArraySubscript;
1150 static Matcher matcher() {
1153 hasBase(ignoringParenImpCasts(
1156 isSafeArraySubscript(),
1160 ))).bind(ArraySubscrTag));
1165 bool IsRelatedToDecl,
1171 DeclUseList getClaimedVarUseSites()
const override {
1172 if (
const auto *DRE =
1185class PointerArithmeticGadget :
public WarningGadget {
1186 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1187 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1193 : WarningGadget(
Kind::PointerArithmetic),
1195 Ptr(Result.
Nodes.getNodeAs<
Expr>(PointerArithmeticPointerTag)) {}
1197 static bool classof(
const Gadget *G) {
1198 return G->getKind() == Kind::PointerArithmetic;
1201 static Matcher matcher() {
1202 auto HasIntegerType =
anyOf(hasType(isInteger()), hasType(
enumType()));
1204 allOf(hasOperatorName(
"+"),
1206 hasLHS(HasIntegerType));
1208 allOf(
anyOf(hasOperatorName(
"+"), hasOperatorName(
"-"),
1209 hasOperatorName(
"+="), hasOperatorName(
"-=")),
1211 hasRHS(HasIntegerType));
1214 .bind(PointerArithmeticTag));
1218 bool IsRelatedToDecl,
1224 DeclUseList getClaimedVarUseSites()
const override {
1235class SpanTwoParamConstructorGadget :
public WarningGadget {
1236 static constexpr const char *
const SpanTwoParamConstructorTag =
1237 "spanTwoParamConstructor";
1242 : WarningGadget(
Kind::SpanTwoParamConstructor),
1244 SpanTwoParamConstructorTag)) {}
1246 static bool classof(
const Gadget *G) {
1247 return G->getKind() == Kind::SpanTwoParamConstructor;
1250 static Matcher matcher() {
1253 parameterCountIs(2)));
1256 unless(isSafeSpanTwoParamConstruct()))
1257 .bind(SpanTwoParamConstructorTag));
1261 return stmt(
unless(ignoreUnsafeBufferInContainer(Handler)), matcher());
1265 bool IsRelatedToDecl,
1271 DeclUseList getClaimedVarUseSites()
const override {
1274 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->
getArg(0))) {
1275 if (isa<VarDecl>(DRE->
getDecl()))
1286class PointerInitGadget :
public FixableGadget {
1288 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1289 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1295 : FixableGadget(
Kind::PointerInit),
1296 PtrInitLHS(Result.
Nodes.getNodeAs<
VarDecl>(PointerInitLHSTag)),
1299 static bool classof(
const Gadget *G) {
1300 return G->getKind() == Kind::PointerInit;
1303 static Matcher matcher() {
1304 auto PtrInitStmt =
declStmt(hasSingleDecl(
1305 varDecl(hasInitializer(ignoringImpCasts(
1307 .bind(PointerInitRHSTag))))
1308 .bind(PointerInitLHSTag)));
1310 return stmt(PtrInitStmt);
1313 virtual std::optional<FixItList>
1319 virtual DeclUseList getClaimedVarUseSites()
const override {
1320 return DeclUseList{PtrInitRHS};
1323 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1324 getStrategyImplications()
const override {
1325 return std::make_pair(PtrInitLHS, cast<VarDecl>(PtrInitRHS->
getDecl()));
1334class PtrToPtrAssignmentGadget :
public FixableGadget {
1336 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1337 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1343 : FixableGadget(
Kind::PtrToPtrAssignment),
1347 static bool classof(
const Gadget *G) {
1348 return G->getKind() == Kind::PtrToPtrAssignment;
1351 static Matcher matcher() {
1353 allOf(hasOperatorName(
"="),
1354 hasRHS(ignoringParenImpCasts(
1356 .bind(PointerAssignRHSTag))),
1358 .bind(PointerAssignLHSTag))));
1363 virtual std::optional<FixItList>
1367 virtual DeclUseList getClaimedVarUseSites()
const override {
1368 return DeclUseList{PtrLHS, PtrRHS};
1371 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1372 getStrategyImplications()
const override {
1373 return std::make_pair(cast<VarDecl>(PtrLHS->
getDecl()),
1374 cast<VarDecl>(PtrRHS->
getDecl()));
1383class CArrayToPtrAssignmentGadget :
public FixableGadget {
1385 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1386 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1392 : FixableGadget(
Kind::CArrayToPtrAssignment),
1396 static bool classof(
const Gadget *G) {
1397 return G->getKind() == Kind::CArrayToPtrAssignment;
1400 static Matcher matcher() {
1402 allOf(hasOperatorName(
"="),
1403 hasRHS(ignoringParenImpCasts(
1405 toSupportedVariable())
1406 .bind(PointerAssignRHSTag))),
1408 .bind(PointerAssignLHSTag))));
1413 virtual std::optional<FixItList>
1417 virtual DeclUseList getClaimedVarUseSites()
const override {
1418 return DeclUseList{PtrLHS, PtrRHS};
1421 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1422 getStrategyImplications()
const override {
1429class UnsafeBufferUsageAttrGadget :
public WarningGadget {
1430 constexpr static const char *
const OpTag =
"attr_expr";
1435 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
1436 Op(Result.
Nodes.getNodeAs<
Expr>(OpTag)) {}
1438 static bool classof(
const Gadget *G) {
1439 return G->getKind() == Kind::UnsafeBufferUsageAttr;
1442 static Matcher matcher() {
1443 auto HasUnsafeFieldDecl =
1446 auto HasUnsafeFnDecl =
1450 memberExpr(HasUnsafeFieldDecl).bind(OpTag)));
1454 bool IsRelatedToDecl,
1460 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1466class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
1467 constexpr static const char *
const OpTag =
"cxx_construct_expr";
1472 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
1475 static bool classof(
const Gadget *G) {
1476 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
1479 static Matcher matcher() {
1480 auto HasUnsafeCtorDecl =
1483 auto HasTwoParamSpanCtorDecl = SpanTwoParamConstructorGadget::matcher();
1490 bool IsRelatedToDecl,
1496 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1503class DataInvocationGadget :
public WarningGadget {
1504 constexpr static const char *
const OpTag =
"data_invocation_expr";
1509 : WarningGadget(
Kind::DataInvocation),
1512 static bool classof(
const Gadget *G) {
1513 return G->getKind() == Kind::DataInvocation;
1516 static Matcher matcher() {
1528 bool IsRelatedToDecl,
1534 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1537class UnsafeLibcFunctionCallGadget :
public WarningGadget {
1539 const Expr *UnsafeArg =
nullptr;
1540 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
1542 constexpr static const char *
const UnsafeSprintfTag =
1543 "UnsafeLibcFunctionCall_sprintf";
1544 constexpr static const char *
const UnsafeSizedByTag =
1545 "UnsafeLibcFunctionCall_sized_by";
1546 constexpr static const char *
const UnsafeStringTag =
1547 "UnsafeLibcFunctionCall_string";
1548 constexpr static const char *
const UnsafeVaListTag =
1549 "UnsafeLibcFunctionCall_va_list";
1561 } WarnedFunKind = OTHERS;
1565 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
1567 if (Result.Nodes.getNodeAs<
Decl>(UnsafeSprintfTag))
1568 WarnedFunKind = SPRINTF;
1569 else if (
auto *
E = Result.Nodes.getNodeAs<
Expr>(UnsafeStringTag)) {
1570 WarnedFunKind = STRING;
1572 }
else if (Result.Nodes.getNodeAs<
CallExpr>(UnsafeSizedByTag)) {
1573 WarnedFunKind = SIZED_BY;
1574 UnsafeArg =
Call->getArg(0);
1575 }
else if (Result.Nodes.getNodeAs<
Decl>(UnsafeVaListTag))
1576 WarnedFunKind = VA_LIST;
1580 return stmt(
unless(ignoreUnsafeLibcCall(Handler)),
1586 functionDecl(libc_func_matchers::isPredefinedUnsafeLibcFunc()),
1590 functionDecl(libc_func_matchers::isUnsafeVaListPrintfFunc())
1591 .bind(UnsafeVaListTag),
1594 functionDecl(libc_func_matchers::isUnsafeSprintfFunc())
1595 .bind(UnsafeSprintfTag)))),
1607 libc_func_matchers::hasUnsafeSnprintfBuffer())
1608 .bind(UnsafeSizedByTag),
1612 libc_func_matchers::hasUnsafePrintfStringArg(
1613 expr().bind(UnsafeStringTag)))));
1616 const Stmt *getBaseStmt()
const {
return Call; }
1621 bool IsRelatedToDecl,
1626 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1632class ULCArraySubscriptGadget :
public FixableGadget {
1634 static constexpr const char *
const ULCArraySubscriptTag =
1635 "ArraySubscriptUnderULC";
1640 : FixableGadget(
Kind::ULCArraySubscript),
1642 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
1645 static bool classof(
const Gadget *G) {
1646 return G->getKind() == Kind::ULCArraySubscript;
1649 static Matcher matcher() {
1651 auto BaseIsArrayOrPtrDRE = hasBase(
1652 ignoringParenImpCasts(
declRefExpr(ArrayOrPtr, toSupportedVariable())));
1659 virtual std::optional<FixItList>
1663 virtual DeclUseList getClaimedVarUseSites()
const override {
1664 if (
const auto *DRE =
1665 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts())) {
1675class UPCStandalonePointerGadget :
public FixableGadget {
1677 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
1682 : FixableGadget(
Kind::UPCStandalonePointer),
1684 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
1687 static bool classof(
const Gadget *G) {
1688 return G->getKind() == Kind::UPCStandalonePointer;
1691 static Matcher matcher() {
1693 auto target =
expr(ignoringParenImpCasts(
1695 .bind(DeclRefExprTag)));
1699 virtual std::optional<FixItList>
1703 virtual DeclUseList getClaimedVarUseSites()
const override {
return {
Node}; }
1706class PointerDereferenceGadget :
public FixableGadget {
1707 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
1708 static constexpr const char *
const OperatorTag =
"op";
1715 : FixableGadget(
Kind::PointerDereference),
1720 static bool classof(
const Gadget *G) {
1721 return G->getKind() == Kind::PointerDereference;
1724 static Matcher matcher() {
1727 hasOperatorName(
"*"),
1728 has(
expr(ignoringParenImpCasts(
1729 declRefExpr(toSupportedVariable()).bind(BaseDeclRefExprTag)))))
1735 DeclUseList getClaimedVarUseSites()
const override {
1736 return {BaseDeclRefExpr};
1739 virtual std::optional<FixItList>
1747class UPCAddressofArraySubscriptGadget :
public FixableGadget {
1749 static constexpr const char *
const UPCAddressofArraySubscriptTag =
1750 "AddressofArraySubscriptUnderUPC";
1755 : FixableGadget(
Kind::ULCArraySubscript),
1757 UPCAddressofArraySubscriptTag)) {
1758 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
1761 static bool classof(
const Gadget *G) {
1762 return G->getKind() == Kind::UPCAddressofArraySubscript;
1765 static Matcher matcher() {
1768 hasOperatorName(
"&"),
1770 ignoringParenImpCasts(
declRefExpr(toSupportedVariable()))))))
1771 .bind(UPCAddressofArraySubscriptTag)))));
1774 virtual std::optional<FixItList>
1778 virtual DeclUseList getClaimedVarUseSites()
const override {
1779 const auto *ArraySubst = cast<ArraySubscriptExpr>(
Node->getSubExpr());
1781 cast<DeclRefExpr>(ArraySubst->getBase()->IgnoreParenImpCasts());
1791class DeclUseTracker {
1792 using UseSetTy = SmallSet<const DeclRefExpr *, 16>;
1793 using DefMapTy = DenseMap<const VarDecl *, const DeclStmt *>;
1796 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
1800 DeclUseTracker() =
default;
1801 DeclUseTracker(
const DeclUseTracker &) =
delete;
1802 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
1803 DeclUseTracker(DeclUseTracker &&) =
default;
1804 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
1807 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
1811 assert(Uses->count(DRE) &&
1812 "DRE not found or claimed by multiple matchers!");
1817 bool hasUnclaimedUses(
const VarDecl *VD)
const {
1819 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
1824 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
1826 for (
auto use : *Uses) {
1828 ReturnSet.insert(use);
1834 void discoverDecl(
const DeclStmt *DS) {
1836 if (
const auto *VD = dyn_cast<VarDecl>(
D)) {
1848 return Defs.lookup(VD);
1857 static constexpr const char *
const UPCPreIncrementTag =
1858 "PointerPreIncrementUnderUPC";
1863 : FixableGadget(Kind::UPCPreIncrement),
1865 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
1869 return G->getKind() == Kind::UPCPreIncrement;
1879 hasUnaryOperand(
declRefExpr(toSupportedVariable())))
1880 .bind(UPCPreIncrementTag)))));
1883 virtual std::optional<FixItList>
1888 return {dyn_cast<DeclRefExpr>(
Node->getSubExpr())};
1896 static constexpr const char *
const UUCAddAssignTag =
1897 "PointerAddAssignUnderUUC";
1898 static constexpr const char *
const OffsetTag =
"Offset";
1901 const Expr *Offset =
nullptr;
1905 : FixableGadget(Kind::UUCAddAssign),
1907 Offset(Result.
Nodes.getNodeAs<
Expr>(OffsetTag)) {
1908 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
1912 return G->getKind() == Kind::UUCAddAssign;
1922 toSupportedVariable())),
1923 hasRHS(
expr().bind(OffsetTag)))
1924 .bind(UUCAddAssignTag)))));
1928 virtual std::optional<FixItList>
1933 return {dyn_cast<DeclRefExpr>(
Node->getLHS())};
1940 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
1941 static constexpr const char *
const DerefOpTag =
"DerefOp";
1942 static constexpr const char *
const AddOpTag =
"AddOp";
1943 static constexpr const char *
const OffsetTag =
"Offset";
1952 : FixableGadget(Kind::DerefSimplePtrArithFixable),
1962 ignoringImpCasts(
declRefExpr(toSupportedVariable()).
1963 bind(BaseDeclRefExprTag)));
1964 auto PlusOverPtrAndInteger =
expr(
anyOf(
1972 hasOperatorName(
"*"),
1973 hasUnaryOperand(ignoringParens(PlusOverPtrAndInteger)))
1978 virtual std::optional<FixItList>
1985 return {BaseDeclRefExpr};
1992 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
1993 WarningGadgetList &WarningGadgets,
1994 DeclUseTracker &Tracker) {
1997 GadgetFinderCallback(FixableGadgetList &FixableGadgets,
1998 WarningGadgetList &WarningGadgets,
1999 DeclUseTracker &Tracker)
2000 : FixableGadgets(FixableGadgets), WarningGadgets(WarningGadgets),
2009 [[maybe_unused]]
int numFound = 0;
2010#define NEXT ++numFound
2013 if (
const auto *DRE = Result.Nodes.getNodeAs<
DeclRefExpr>(
"any_dre")) {
2014 Tracker.discoverUse(DRE);
2018 if (
const auto *DS = Result.Nodes.getNodeAs<
DeclStmt>(
"any_ds")) {
2019 Tracker.discoverDecl(DS);
2026#define FIXABLE_GADGET(name) \
2027 if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
2028 FixableGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2031#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2032#define WARNING_GADGET(name) \
2033 if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
2034 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2037#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2039 assert(numFound >= 1 &&
"Gadgets not found in match result!");
2040 assert(numFound <= 1 &&
"Conflicting bind tags in gadgets!");
2043 FixableGadgetList &FixableGadgets;
2044 WarningGadgetList &WarningGadgets;
2045 DeclUseTracker &Tracker;
2049 GadgetFinderCallback CB{FixableGadgets, WarningGadgets, Tracker};
2054 forEachDescendantEvaluatedStmt(
stmt(
anyOf(
2057 allOf(x ## Gadget::matcher().bind(#x), \
2058 notInSafeBufferOptOut(&Handler)),
2060 allOf(x ## Gadget::matcher(&Handler).bind(#x), \
2061 notInSafeBufferOptOut(&Handler)),
2062#include
"clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2071 if (EmitSuggestions) {
2077 x ## Gadget::matcher().bind(#x),
2078#include
"clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2100 return N1->getBeginLoc().getRawEncoding() <
2101 N2->getBeginLoc().getRawEncoding();
2106 std::map<const VarDecl *, std::set<const WarningGadget *>,
2120 for (
auto &G : AllUnsafeOperations) {
2121 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
2123 bool AssociatedWithVarDecl =
false;
2124 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
2125 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2126 result.
byVar[VD].insert(G.get());
2127 AssociatedWithVarDecl =
true;
2131 if (!AssociatedWithVarDecl) {
2132 result.
noVar.push_back(G.get());
2140 std::map<const VarDecl *, std::set<const FixableGadget *>,
2150 for (
auto &F : AllFixableOperations) {
2151 DeclUseList DREs = F->getClaimedVarUseSites();
2154 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2155 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
2159 return FixablesForUnsafeVars;
2166 std::vector<const FixItHint *> All;
2170 std::sort(All.begin(), All.end(),
2172 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
2173 H2->RemoveRange.getBegin());
2181 Hint->RemoveRange.getBegin())) {
2193std::optional<FixItList>
2194PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2195 const auto *LeftVD = cast<VarDecl>(PtrLHS->
getDecl());
2196 const auto *RightVD = cast<VarDecl>(PtrRHS->
getDecl());
2197 switch (S.lookup(LeftVD)) {
2198 case FixitStrategy::Kind::Span:
2199 if (S.lookup(RightVD) == FixitStrategy::Kind::Span)
2201 return std::nullopt;
2202 case FixitStrategy::Kind::Wontfix:
2203 return std::nullopt;
2204 case FixitStrategy::Kind::Iterator:
2205 case FixitStrategy::Kind::Array:
2206 return std::nullopt;
2207 case FixitStrategy::Kind::Vector:
2208 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2210 return std::nullopt;
2217std::optional<FixItList>
2218CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2219 const auto *LeftVD = cast<VarDecl>(PtrLHS->
getDecl());
2220 const auto *RightVD = cast<VarDecl>(PtrRHS->
getDecl());
2237 if (S.lookup(LeftVD) == FixitStrategy::Kind::Span) {
2238 if (S.lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
2241 }
else if (S.lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
2242 if (S.lookup(RightVD) == FixitStrategy::Kind::Array) {
2246 return std::nullopt;
2249std::optional<FixItList>
2251 const auto *LeftVD = PtrInitLHS;
2252 const auto *RightVD = cast<VarDecl>(PtrInitRHS->
getDecl());
2253 switch (S.lookup(LeftVD)) {
2254 case FixitStrategy::Kind::Span:
2255 if (S.lookup(RightVD) == FixitStrategy::Kind::Span)
2257 return std::nullopt;
2258 case FixitStrategy::Kind::Wontfix:
2259 return std::nullopt;
2260 case FixitStrategy::Kind::Iterator:
2261 case FixitStrategy::Kind::Array:
2262 return std::nullopt;
2263 case FixitStrategy::Kind::Vector:
2264 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2266 return std::nullopt;
2272 if (ConstVal->isNegative())
2279std::optional<FixItList>
2280ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2281 if (
const auto *DRE =
2282 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts()))
2283 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2284 switch (S.lookup(VD)) {
2285 case FixitStrategy::Kind::Span: {
2292 return std::nullopt;
2296 case FixitStrategy::Kind::Array:
2298 case FixitStrategy::Kind::Wontfix:
2299 case FixitStrategy::Kind::Iterator:
2300 case FixitStrategy::Kind::Vector:
2301 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2304 return std::nullopt;
2307static std::optional<FixItList>
2310std::optional<FixItList>
2311UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2312 auto DREs = getClaimedVarUseSites();
2313 const auto *VD = cast<VarDecl>(DREs.front()->getDecl());
2315 switch (S.lookup(VD)) {
2316 case FixitStrategy::Kind::Span:
2318 case FixitStrategy::Kind::Wontfix:
2319 case FixitStrategy::Kind::Iterator:
2320 case FixitStrategy::Kind::Array:
2321 return std::nullopt;
2322 case FixitStrategy::Kind::Vector:
2323 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2325 return std::nullopt;
2330 static const char *
const EOL =
"\n";
2337 std::string
s = std::string(
"<# ");
2338 s += HintTextToUser;
2344template <
typename NodeTy>
2345static std::optional<SourceLocation>
2354 return std::nullopt;
2358template <
typename NodeTy>
2366 return std::nullopt;
2373 std::optional<SourceLocation> LastCharLoc =
getPastLoc(
E,
SM, LangOpts);
2380 return std::nullopt;
2393 return std::nullopt;
2405static std::optional<StringRef>
2414 return std::nullopt;
2415 return getRangeText({ParmIdentBeginLoc, ParmIdentEndLoc},
SM, LangOpts);
2428 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
2429 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
2430 VD->getBeginLoc())) &&
2431 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
2432 At->getRange().getBegin()));
2436 AttrRangeOverlapping;
2460static std::optional<std::string>
2463 std::optional<Qualifiers> *QualifiersToAppend) {
2468 "Expecting a VarDecl of type of pointer to object type");
2477 case TypeLoc::ConstantArray:
2478 case TypeLoc::IncompleteArray:
2479 case TypeLoc::VariableArray:
2480 case TypeLoc::DependentSizedArray:
2481 case TypeLoc::Decayed:
2482 assert(isa<ParmVarDecl>(VD) &&
"An array type shall not be treated as a "
2483 "pointer type unless it decays.");
2486 case TypeLoc::Pointer:
2490 return std::nullopt;
2495 return std::nullopt;
2503 return std::nullopt;
2510 if (!PteEndOfTokenLoc.
isValid())
2513 return std::nullopt;
2514 if (!
SM.isBeforeInTranslationUnit(PteEndOfTokenLoc, IdentLoc)) {
2521 return std::nullopt;
2556 std::optional<Qualifiers> Quals = std::nullopt) {
2557 const char *
const SpanOpen =
"std::span<";
2560 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
2561 return SpanOpen + EltTyText.str() +
'>';
2564std::optional<FixItList>
2566 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->
getDecl());
2568 if (VD &&
s.lookup(VD) == FixitStrategy::Kind::Span) {
2572 if (ConstVal->isNegative())
2573 return std::nullopt;
2601 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
2603 return std::nullopt;
2608 std::optional<SourceLocation> AddOpLocation =
2610 std::optional<SourceLocation> DerefOpLocation =
2613 if (!AddOpLocation || !DerefOpLocation)
2614 return std::nullopt;
2624 return std::nullopt;
2627std::optional<FixItList>
2628PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
2630 switch (S.lookup(VD)) {
2631 case FixitStrategy::Kind::Span: {
2639 if (
auto LocPastOperand =
2646 case FixitStrategy::Kind::Iterator:
2647 case FixitStrategy::Kind::Array:
2648 return std::nullopt;
2649 case FixitStrategy::Kind::Vector:
2650 llvm_unreachable(
"FixitStrategy not implemented yet!");
2651 case FixitStrategy::Kind::Wontfix:
2652 llvm_unreachable(
"Invalid strategy!");
2655 return std::nullopt;
2662 std::optional<SourceLocation> EndOfOperand =
2668 return std::nullopt;
2673std::optional<FixItList>
2674UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
2675 const auto VD = cast<VarDecl>(
Node->getDecl());
2676 switch (S.lookup(VD)) {
2677 case FixitStrategy::Kind::Array:
2678 case FixitStrategy::Kind::Span: {
2683 case FixitStrategy::Kind::Wontfix:
2684 case FixitStrategy::Kind::Iterator:
2685 return std::nullopt;
2686 case FixitStrategy::Kind::Vector:
2687 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2690 return std::nullopt;
2695static std::optional<FixItList>
2697 const auto *ArraySub = cast<ArraySubscriptExpr>(
Node->getSubExpr());
2698 const auto *DRE = cast<DeclRefExpr>(ArraySub->getBase()->IgnoreImpCasts());
2702 const Expr *Idx = ArraySub->getIdx();
2705 std::stringstream SS;
2706 bool IdxIsLitZero =
false;
2709 if ((*ICE).isZero())
2710 IdxIsLitZero =
true;
2711 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
2713 return std::nullopt;
2717 SS << (*DreString).str() <<
".data()";
2719 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
2721 return std::nullopt;
2723 SS <<
"&" << (*DreString).str() <<
".data()"
2724 <<
"[" << (*IndexString).str() <<
"]";
2730std::optional<FixItList>
2734 if (DREs.size() != 1)
2735 return std::nullopt;
2737 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
2738 if (S.lookup(VD) == FixitStrategy::Kind::Span) {
2742 StringRef varName = VD->
getName();
2746 return std::nullopt;
2751 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
2755 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
2757 if (!AddAssignLocation)
2758 return std::nullopt;
2769 return std::nullopt;
2772std::optional<FixItList>
2776 if (DREs.size() != 1)
2777 return std::nullopt;
2779 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
2780 if (S.lookup(VD) == FixitStrategy::Kind::Span) {
2782 std::stringstream SS;
2783 StringRef varName = VD->
getName();
2787 SS <<
"(" << varName.data() <<
" = " << varName.data()
2788 <<
".subspan(1)).data()";
2789 std::optional<SourceLocation> PreIncLocation =
2791 if (!PreIncLocation)
2792 return std::nullopt;
2799 return std::nullopt;
2817static std::optional<FixItList>
2819 const StringRef UserFillPlaceHolder) {
2827 if (
Init->isNullPointerConstant(
2832 NPC_ValueDependentIsNotNull)) {
2833 std::optional<SourceLocation> InitLocation =
2836 return std::nullopt;
2844 std::string ExtentText = UserFillPlaceHolder.data();
2845 StringRef One =
"1";
2850 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
2855 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
2856 if (!Ext->HasSideEffects(Ctx)) {
2857 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
2859 return std::nullopt;
2860 ExtentText = *ExtentString;
2862 }
else if (!CxxNew->isArray())
2874 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
2875 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
2876 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
2883 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
2886 return std::nullopt;
2888 StrBuffer.append(
", ");
2889 StrBuffer.append(ExtentText);
2890 StrBuffer.append(
"}");
2896#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
2897 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
2898 "failed to produce fixit for declaration '" + \
2899 (D)->getNameAsString() + "'" + (Msg))
2901#define DEBUG_NOTE_DECL_FAIL(D, Msg)
2907static std::optional<std::string>
2911 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
2916 return std::nullopt;
2918 std::string SpanTyText =
"std::span<";
2920 SpanTyText.append(*PteTyText);
2922 if (PteTyQualifiers) {
2923 SpanTyText.append(
" ");
2924 SpanTyText.append(PteTyQualifiers->getAsString());
2926 SpanTyText.append(
">");
2945 const StringRef UserFillPlaceHolder,
2959 std::stringstream SS;
2964 std::optional<FixItList> InitFixIts =
2968 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
2969 std::make_move_iterator(InitFixIts->end()));
2976 if (!EndLocForReplacement.
isValid()) {
3026static std::optional<FixItList>
3032 return std::nullopt;
3037 std::vector<std::string> NewTysTexts(NumParms);
3038 std::vector<bool> ParmsMask(NumParms,
false);
3039 bool AtLeastOneParmToFix =
false;
3041 for (
unsigned i = 0; i < NumParms; i++) {
3044 if (S.lookup(PVD) == FixitStrategy::Kind::Wontfix)
3046 if (S.lookup(PVD) != FixitStrategy::Kind::Span)
3048 return std::nullopt;
3050 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3051 std::optional<std::string> PteTyText =
3056 return std::nullopt;
3060 ParmsMask[i] =
true;
3061 AtLeastOneParmToFix =
true;
3063 if (!AtLeastOneParmToFix)
3070 const auto NewOverloadSignatureCreator =
3071 [&
SM, &LangOpts, &NewTysTexts,
3072 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3073 std::stringstream SS;
3081 SS << Prefix->str();
3083 return std::nullopt;
3087 for (
unsigned i = 0; i < NumParms; i++) {
3095 SS << NewTysTexts[i];
3098 SS <<
' ' << II->
getName().str();
3099 }
else if (
auto ParmTypeText =
3103 SS << ParmTypeText->str();
3105 return std::nullopt;
3106 if (i != NumParms - 1)
3115 const auto OldOverloadDefCreator =
3116 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3117 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3118 std::stringstream SS;
3126 << FDPrefix->str() <<
"{";
3128 return std::nullopt;
3131 SS <<
"return " << FunQualName->str() <<
"(";
3133 return std::nullopt;
3137 for (
unsigned i = 0; i < NumParms; i++) {
3146 return std::nullopt;
3153 if (i != NumParms - 1)
3164 std::optional<SourceLocation>
Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3168 if (FReDecl->isThisDeclarationADefinition()) {
3169 assert(FReDecl == FD &&
"inconsistent function definition");
3172 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3178 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3181 FReDecl->getBeginLoc(),
" ")));
3184 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3206 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3222 std::stringstream SS;
3225 if (PteTyQualifiers)
3234 SS <<
' ' << PVDNameText->str();
3240 const DeclUseTracker &Tracker,
3243 const DeclStmt *DS = Tracker.lookupDecl(VD);
3246 " : variables declared this way not implemented yet");
3270 const QualType &ArrayEltT = CAT->getElementType();
3271 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
3280 auto MaybeElemTypeTxt =
3283 if (!MaybeElemTypeTxt)
3285 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
3290 while (NextTok && !NextTok->is(tok::l_square) &&
3303 if (!MaybeArraySizeTxt)
3305 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
3306 if (ArraySizeTxt.empty()) {
3317 std::optional<StringRef> IdentText =
3326 raw_svector_ostream OS(Replacement);
3327 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
3328 << IdentText->str();
3338 const DeclUseTracker &Tracker,
3341 const DeclStmt *DS = Tracker.lookupDecl(VD);
3342 assert(DS &&
"Fixing non-local variables not implemented yet!");
3361 const DeclUseTracker &Tracker,
ASTContext &Ctx,
3363 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
3364 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
3365 if (!FD || FD !=
D) {
3376 if (FD->isMain() || FD->isConstexpr() ||
3377 FD->getTemplatedKind() != FunctionDecl::TemplatedKind::TK_NonTemplate ||
3380 isa<CXXMethodDecl>(FD) ||
3382 (FD->hasBody() && isa<CXXTryStmt>(FD->getBody())) ||
3383 FD->isOverloadedOperator()) {
3390 case FixitStrategy::Kind::Span: {
3392 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
3401 case FixitStrategy::Kind::Array: {
3408 case FixitStrategy::Kind::Iterator:
3409 case FixitStrategy::Kind::Vector:
3410 llvm_unreachable(
"FixitStrategy not implemented yet!");
3411 case FixitStrategy::Kind::Wontfix:
3412 llvm_unreachable(
"Invalid strategy!");
3414 llvm_unreachable(
"Unknown strategy!");
3422 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
3433 return isa<ParmVarDecl>(VD) &&
3441 std::map<const VarDecl *, FixItList> &FixItsForVariable,
3446 for (
const auto &[VD, Ignore] : FixItsForVariable) {
3448 if (llvm::any_of(Grp,
3449 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
3450 return !FixItsForVariable.count(GrpMember);
3455 ToErase.push_back(
Member);
3458 for (
auto *VarToErase : ToErase)
3459 FixItsForVariable.erase(VarToErase);
3470 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
3474 FixItList FixItsSharedByParms{};
3476 std::optional<FixItList> OverloadFixes =
3479 if (OverloadFixes) {
3480 FixItsSharedByParms.append(*OverloadFixes);
3486 FixItsForVariable.erase(
Member);
3488 return FixItsSharedByParms;
3492static std::map<const VarDecl *, FixItList>
3501 std::map<const VarDecl *, FixItList> FixItsForVariable;
3506 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
3507 FixItsForVariable[VD] =
3508 fixVariable(VD, S.lookup(VD),
D, Tracker, Ctx, Handler);
3511 if (FixItsForVariable[VD].empty()) {
3512 FixItsForVariable.erase(VD);
3515 for (
const auto &F : Fixables) {
3516 std::optional<FixItList> Fixits = F->getFixits(S);
3519 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
3520 Fixits->begin(), Fixits->end());
3525 VD, F->getSourceLoc(),
3526 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
3529 FixItsForVariable.erase(VD);
3548 FixItList FixItsSharedByParms{};
3550 if (
auto *FD = dyn_cast<FunctionDecl>(
D))
3552 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
3556 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
3559 for (
auto &[Var, Ignore] : FixItsForVariable) {
3560 bool AnyParm =
false;
3561 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
3563 for (
const VarDecl *GrpMate : VarGroupForVD) {
3566 if (FixItsForVariable.count(GrpMate))
3567 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
3571 assert(!FixItsSharedByParms.empty() &&
3572 "Should not try to fix a parameter that does not belong to a "
3574 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
3581 for (
auto Iter = FinalFixItsForVariable.begin();
3582 Iter != FinalFixItsForVariable.end();)
3585 Iter = FinalFixItsForVariable.erase(
Iter);
3588 return FinalFixItsForVariable;
3591template <
typename VarDeclIterTy>
3595 for (
const VarDecl *VD : UnsafeVars) {
3597 S.set(VD, FixitStrategy::Kind::Array);
3599 S.set(VD, FixitStrategy::Kind::Span);
3606 const std::vector<VarGrpTy> Groups;
3607 const std::map<const VarDecl *, unsigned> &VarGrpMap;
3608 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
3612 const std::vector<VarGrpTy> &Groups,
3613 const std::map<const VarDecl *, unsigned> &VarGrpMap,
3614 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
3615 : Groups(Groups), VarGrpMap(VarGrpMap),
3616 GrpsUnionForParms(GrpsUnionForParms) {}
3619 if (GrpsUnionForParms.contains(Var)) {
3622 return GrpsUnionForParms.getArrayRef();
3627 auto It = VarGrpMap.find(Var);
3629 if (It == VarGrpMap.end())
3631 return Groups[It->second];
3635 return GrpsUnionForParms.getArrayRef();
3640 WarningGadgetList WarningGadgets, DeclUseTracker Tracker,
3642 if (!EmitSuggestions) {
3646 for (
const auto &G : WarningGadgets) {
3647 G->handleUnsafeOperation(Handler,
false,
3653 assert(FixableGadgets.size() == 0 &&
3654 "Fixable gadgets found but suggestions not requested!");
3660 if (!WarningGadgets.empty()) {
3664 for (
const auto &G : FixableGadgets) {
3665 for (
const auto *DRE : G->getClaimedVarUseSites()) {
3666 Tracker.claimUse(DRE);
3682 if (WarningGadgets.empty())
3690 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
3693 for (
auto it = FixablesForAllVars.
byVar.cbegin();
3694 it != FixablesForAllVars.
byVar.cend();) {
3696 if ((!it->first->isLocalVarDecl() && !isa<ParmVarDecl>(it->first))) {
3699 (
"failed to produce fixit for '" +
3700 it->first->getNameAsString() +
3701 "' : neither local nor a parameter"));
3703 it = FixablesForAllVars.
byVar.erase(it);
3704 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
3707 (
"failed to produce fixit for '" +
3708 it->first->getNameAsString() +
3709 "' : has a reference type"));
3711 it = FixablesForAllVars.
byVar.erase(it);
3712 }
else if (Tracker.hasUnclaimedUses(it->first)) {
3713 it = FixablesForAllVars.
byVar.erase(it);
3714 }
else if (it->first->isInitCapture()) {
3717 (
"failed to produce fixit for '" +
3718 it->first->getNameAsString() +
3719 "' : init capture"));
3721 it = FixablesForAllVars.
byVar.erase(it);
3728 for (
const auto &it : UnsafeOps.
byVar) {
3729 const VarDecl *
const UnsafeVD = it.first;
3730 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
3731 if (UnclaimedDREs.empty())
3735 std::string UnclaimedUseTrace =
3740 (
"failed to produce fixit for '" + UnfixedVDName +
3741 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
3742 UnclaimedUseTrace));
3748 using DepMapTy = DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
3749 DepMapTy DependenciesMap{};
3750 DepMapTy PtrAssignmentGraph{};
3752 for (
auto it : FixablesForAllVars.
byVar) {
3753 for (
const FixableGadget *fixable : it.second) {
3754 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
3755 fixable->getStrategyImplications();
3757 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
3758 PtrAssignmentGraph[Impl.first].insert(Impl.second);
3780 std::set<const VarDecl *> VisitedVarsDirected{};
3781 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
3782 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
3784 std::queue<const VarDecl *> QueueDirected{};
3785 QueueDirected.push(Var);
3786 while (!QueueDirected.empty()) {
3787 const VarDecl *CurrentVar = QueueDirected.front();
3788 QueueDirected.pop();
3789 VisitedVarsDirected.insert(CurrentVar);
3790 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
3791 for (
const VarDecl *Adj : AdjacentNodes) {
3792 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
3793 QueueDirected.push(Adj);
3795 DependenciesMap[Var].insert(Adj);
3796 DependenciesMap[Adj].insert(Var);
3803 std::vector<VarGrpTy> Groups;
3807 std::map<const VarDecl *, unsigned> VarGrpMap;
3809 llvm::SetVector<const VarDecl *>
3814 std::set<const VarDecl *> VisitedVars{};
3815 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
3816 if (VisitedVars.find(Var) == VisitedVars.end()) {
3817 VarGrpTy &VarGroup = Groups.emplace_back();
3818 std::queue<const VarDecl *> Queue{};
3821 while (!Queue.empty()) {
3822 const VarDecl *CurrentVar = Queue.front();
3824 VisitedVars.insert(CurrentVar);
3825 VarGroup.push_back(CurrentVar);
3826 auto AdjacentNodes = DependenciesMap[CurrentVar];
3827 for (
const VarDecl *Adj : AdjacentNodes) {
3828 if (VisitedVars.find(Adj) == VisitedVars.end()) {
3834 bool HasParm =
false;
3835 unsigned GrpIdx = Groups.size() - 1;
3837 for (
const VarDecl *
V : VarGroup) {
3838 VarGrpMap[
V] = GrpIdx;
3843 GrpsUnionForParms.insert(VarGroup.begin(), VarGroup.end());
3865 for (
auto I = FixablesForAllVars.
byVar.begin();
3866 I != FixablesForAllVars.
byVar.end();) {
3868 if (!VisitedVars.count((*I).first)) {
3870 I = FixablesForAllVars.
byVar.erase(I);
3878 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
3880 return FixablesForAllVars.
byVar.count(
V);
3884 if (isa<NamedDecl>(
D))
3887 FixItsForVariableGroup =
3889 Tracker, Handler, VarGrpMgr);
3891 for (
const auto &G : UnsafeOps.
noVar) {
3892 G->handleUnsafeOperation(Handler,
false,
3896 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
3897 auto FixItsIt = FixItsForVariableGroup.find(VD);
3899 FixItsIt != FixItsForVariableGroup.end()
3900 ? std::move(FixItsIt->second)
3903 for (
const auto &G : WarningGadgets) {
3904 G->handleUnsafeOperation(Handler,
true,
3912 bool EmitSuggestions) {
3921 if (
const auto *FD = dyn_cast<FunctionDecl>(
D)) {
3925 if (
const auto *MD = dyn_cast<CXXMethodDecl>(
D)) {
3926 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
3931 if (FReDecl->isExternC()) {
3934 EmitSuggestions =
false;
3939 Stmts.push_back(FD->getBody());
3941 if (
const auto *ID = dyn_cast<CXXConstructorDecl>(
D)) {
3943 Stmts.push_back(CI->getInit());
3946 }
else if (isa<BlockDecl>(
D) || isa<ObjCMethodDecl>(
D)) {
3950 assert(!Stmts.empty());
3952 FixableGadgetList FixableGadgets;
3953 WarningGadgetList WarningGadgets;
3954 DeclUseTracker Tracker;
3955 for (
Stmt *S : Stmts) {
3957 WarningGadgets, Tracker);
3959 applyGadgets(
D, std::move(FixableGadgets), std::move(WarningGadgets),
3960 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.
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
bool isValueDependent() const
Determines whether the value of this expression depends on.
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 std::optional< Token > findNextToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts, bool IncludeComments=false)
Finds the token that comes right after the given location.
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.
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)