28#include "llvm/ADT/APInt.h"
29#include "llvm/ADT/APSInt.h"
30#include "llvm/ADT/STLFunctionalExtras.h"
31#include "llvm/ADT/SmallSet.h"
32#include "llvm/ADT/SmallVector.h"
33#include "llvm/ADT/StringRef.h"
47 std::string VisitStmt(
const Stmt *S) {
return S->getStmtClassName(); }
50 return "BinaryOperator(" + BO->
getOpcodeStr().str() +
")";
64static std::string getDREAncestorString(
const DeclRefExpr *DRE,
68 StmtDebugPrinter StmtPriner;
71 SS << StmtPriner.Visit(St);
75 if (StParents.
size() > 1)
76 return "unavailable due to multiple parents";
77 if (StParents.
empty())
98 virtual ~FastMatcher() =
default;
104 template <
typename T>
const T *getNodeAs(StringRef ID)
const {
105 auto It =
Nodes.find(ID);
106 if (It ==
Nodes.end()) {
109 return It->second.get<
T>();
115 llvm::StringMap<DynTypedNode>
Nodes;
119#define SIZED_CONTAINER_OR_VIEW_LIST \
120 "span", "array", "vector", "basic_string_view", "basic_string", \
131 bool FindAll,
bool ignoreUnevaluatedContext,
133 : Matcher(&Matcher), FindAll(FindAll), Matches(
false),
134 ignoreUnevaluatedContext(ignoreUnevaluatedContext),
135 ActiveASTContext(&Context), Handler(&NewHandler) {
164 if (isa<FunctionDecl, BlockDecl, ObjCMethodDecl>(
Node))
172 if (ignoreUnevaluatedContext)
174 return DynamicRecursiveASTVisitor::TraverseGenericSelectionExpr(
Node);
180 if (ignoreUnevaluatedContext)
182 return DynamicRecursiveASTVisitor::TraverseUnaryExprOrTypeTraitExpr(
Node);
186 bool TraverseQualifier)
override {
188 if (ignoreUnevaluatedContext)
190 return DynamicRecursiveASTVisitor::TraverseTypeOfExprTypeLoc(
191 Node, TraverseQualifier);
195 bool TraverseQualifier)
override {
197 if (ignoreUnevaluatedContext)
199 return DynamicRecursiveASTVisitor::TraverseDecltypeTypeLoc(
200 Node, TraverseQualifier);
205 if (ignoreUnevaluatedContext)
207 return DynamicRecursiveASTVisitor::TraverseCXXNoexceptExpr(
Node);
212 if (ignoreUnevaluatedContext)
214 return DynamicRecursiveASTVisitor::TraverseCXXTypeidExpr(
Node);
220 return DynamicRecursiveASTVisitor::TraverseCXXDefaultInitExpr(
Node);
236 template <
typename T>
bool match(
const T &
Node) {
246 FastMatcher *
const Matcher;
250 bool ignoreUnevaluatedContext;
267 FastMatcher &Matcher) {
275 FastMatcher &Matcher) {
303 const Stmt *S,
const llvm::function_ref<
void(
const Expr *)> OnResult) {
304 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(S);
305 CE && CE->getCastKind() == CastKind::CK_LValueToRValue)
306 OnResult(CE->getSubExpr());
307 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
315 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
324 if (
auto *CE = dyn_cast<CallExpr>(S)) {
325 if (
const auto *FnDecl = CE->getDirectCallee();
326 FnDecl && FnDecl->hasAttr<UnsafeBufferUsageAttr>())
335 if (
auto *CE = dyn_cast<CastExpr>(S)) {
336 if (CE->getCastKind() != CastKind::CK_PointerToIntegral &&
337 CE->getCastKind() != CastKind::CK_PointerToBoolean)
341 InnerMatcher(CE->getSubExpr());
345 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
359 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
365 InnerMatcher(BO->
getLHS());
366 InnerMatcher(BO->
getRHS());
384 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
389 if (
auto *CS = dyn_cast<CompoundStmt>(S)) {
390 for (
auto *Child : CS->body())
393 if (
auto *IfS = dyn_cast<IfStmt>(S)) {
395 InnerMatcher(IfS->getThen());
397 InnerMatcher(IfS->getElse());
448 case Stmt::DeclRefExprClass:
449 return cast<DeclRefExpr>(E1)->getDecl() == cast<DeclRefExpr>(E2)->getDecl();
450 case Stmt::BinaryOperatorClass: {
451 auto BO2 = cast<BinaryOperator>(E2);
453 BO2->getLHS(), BO2->getOpcode(),
479 dyn_cast<CXXMemberCallExpr>(Size->IgnoreParenImpCasts())) {
480 auto *DREOfPtr = dyn_cast<DeclRefExpr>(
481 MCEPtr->getImplicitObjectArgument()->IgnoreParenImpCasts());
482 auto *DREOfSize = dyn_cast<DeclRefExpr>(
483 MCESize->getImplicitObjectArgument()->IgnoreParenImpCasts());
485 if (!DREOfPtr || !DREOfSize)
489 if (DREOfPtr->getDecl() != DREOfSize->getDecl())
491 if (MCEPtr->getMethodDecl()->getName() !=
"data")
494 if (!MCEPtr->getRecordDecl()->isInStdNamespace())
497 auto *ObjII = MCEPtr->getRecordDecl()->getIdentifier();
504 if (!((AcceptSizeBytes &&
505 MCESize->getMethodDecl()->getName() ==
"size_bytes") ||
510 MCESize->getMethodDecl()->getName() ==
"size"))
520 if (Size->EvaluateAsInt(ER, Ctx)) {
526 return llvm::APSInt::compareValues(
527 SizeInt, llvm::APSInt(CAT->getSize(),
true)) == 0;
535 return UO && UO->
getOpcode() == UnaryOperator::Opcode::UO_AddrOf;
537 auto *FnDecl = CE->getDirectCallee();
539 return FnDecl && FnDecl->getNameAsString() ==
"addressof" &&
540 FnDecl->isInStdNamespace();
567 assert(
Node.getNumArgs() == 2 &&
568 "expecting a two-parameter std::span constructor");
569 const Expr *Arg0 =
Node.getArg(0)->IgnoreParenImpCasts();
570 const Expr *Arg1 =
Node.getArg(1)->IgnoreParenImpCasts();
571 auto HaveEqualConstantValues = [&Ctx](
const Expr *E0,
const Expr *E1) {
573 if (
auto E1CV = E1->getIntegerConstantExpr(Ctx)) {
574 return llvm::APSInt::compareValues(*E0CV, *E1CV) == 0;
578 auto AreSameDRE = [](
const Expr *E0,
const Expr *E1) {
579 if (
auto *DRE0 = dyn_cast<DeclRefExpr>(E0))
580 if (
auto *DRE1 = dyn_cast<DeclRefExpr>(E1)) {
581 return DRE0->getDecl() == DRE1->getDecl();
587 if (Arg1CV && Arg1CV->isZero())
593 case Stmt::CXXNewExprClass:
594 if (
auto Size = cast<CXXNewExpr>(Arg0)->getArraySize()) {
596 return AreSameDRE((*Size)->IgnoreImplicit(), Arg1) ||
597 HaveEqualConstantValues(*Size, Arg1);
600 if (!cast<CXXNewExpr>(Arg0)->hasPlaceholderType()) {
602 return Arg1CV && Arg1CV->isOne();
610 if (
auto CCast = dyn_cast<CStyleCastExpr>(Arg0)) {
611 if (!CCast->getType()->isPointerType())
619 if (
const auto *
Call = dyn_cast<CallExpr>(CCast->getSubExpr())) {
621 if (
auto *AllocAttr = FD->getAttr<AllocSizeAttr>()) {
622 const Expr *EleSizeExpr =
623 Call->getArg(AllocAttr->getElemSizeParam().getASTIndex());
625 ParamIdx NumElemIdx = AllocAttr->getNumElemsParam();
632 if (
auto BO = dyn_cast<BinaryOperator>(Arg1))
639 auto IsMethodCallToSizedObject = [](
const Stmt *
Node, StringRef MethodName) {
640 if (
const auto *MC = dyn_cast<CXXMemberCallExpr>(
Node)) {
641 const auto *MD = MC->getMethodDecl();
642 const auto *RD = MC->getRecordDecl();
645 if (
auto *II = RD->getDeclName().getAsIdentifierInfo();
646 II && RD->isInStdNamespace())
649 MD->getName() == MethodName;
654 if (IsMethodCallToSizedObject(Arg0,
"begin") &&
655 IsMethodCallToSizedObject(Arg1,
"end"))
658 cast<CXXMemberCallExpr>(Arg0)
659 ->getImplicitObjectArgument()
660 ->IgnoreParenImpCasts(),
661 cast<CXXMemberCallExpr>(Arg1)
662 ->getImplicitObjectArgument()
663 ->IgnoreParenImpCasts());
679 if (
const auto *CATy =
680 dyn_cast<ConstantArrayType>(
Node.getBase()
681 ->IgnoreParenImpCasts()
683 ->getUnqualifiedDesugaredType())) {
684 limit = CATy->getLimitedSize();
685 }
else if (
const auto *SLiteral = dyn_cast<clang::StringLiteral>(
686 Node.getBase()->IgnoreParenImpCasts())) {
687 limit = SLiteral->getLength() + 1;
693 const Expr *IndexExpr =
Node.getIdx();
696 llvm::APSInt ArrIdx = EVResult.
Val.
getInt();
699 if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit)
701 }
else if (
const auto *BE = dyn_cast<BinaryOperator>(IndexExpr)) {
704 if (BE->getOpcode() != BO_And && BE->getOpcode() != BO_Rem)
707 const Expr *LHS = BE->getLHS();
708 const Expr *RHS = BE->getRHS();
710 if (BE->getOpcode() == BO_Rem) {
717 llvm::APSInt result = EVResult.
Val.
getInt();
718 if (result.isNonNegative() && result.getLimitedValue() <= limit)
729 llvm::APSInt result = EVResult.
Val.
getInt();
730 if (result.isNonNegative() && result.getLimitedValue() < limit)
754 StringRef
matchName(StringRef FunName,
bool isBuiltin) {
756 if (isBuiltin && FunName.starts_with(
"__builtin_"))
760 FunName.drop_front(10 ));
762 if (FunName.starts_with(
"__asan_"))
770 if (Name.starts_with(
"__") && Name.ends_with(
"_chk"))
772 Name.drop_front(2).drop_back(4) );
777 if (Name.ends_with(
"_s"))
778 return Name.drop_back(2 );
811 bool isKprintf =
false) {
812 class StringFormatStringHandler
816 const Expr *&UnsafeArg;
830 unsigned PArgIdx = -1;
834 if (0 < PArgIdx && PArgIdx < Call->getNumArgs()) {
835 const Expr *PArg =
Call->getArg(PArgIdx);
838 if (
auto *CE = dyn_cast<CastExpr>(PArg);
839 CE && CE->getType()->isSignedIntegerType())
840 PArg = CE->getSubExpr();
844 analyze_printf::OptionalAmount::HowSpecified::Constant) {
846 llvm::APSInt PArgVal = llvm::APSInt(
856 StringFormatStringHandler(
const CallExpr *
Call,
unsigned FmtArgIdx,
858 :
Call(
Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx) {}
861 const char *startSpecifier,
862 unsigned specifierLen,
864 if (FS.getConversionSpecifier().getKind() !=
865 analyze_printf::PrintfConversionSpecifier::sArg)
868 unsigned ArgIdx = FS.getPositionalArgIndex() + FmtArgIdx;
870 if (!(0 < ArgIdx && ArgIdx < Call->getNumArgs()))
874 const Expr *Arg =
Call->getArg(ArgIdx);
882 auto LengthModifier = FS.getLengthModifier();
884 bool IsArgTypeValid =
886 (LengthModifier.getKind() == LengthModifier.AsWideChar
890 if (
auto *Precision = getPrecisionAsExpr(FS.getPrecision(),
Call);
891 Precision && IsArgTypeValid)
895 UnsafeArg =
Call->getArg(ArgIdx);
900 const Expr *Fmt =
Call->getArg(FmtArgIdx);
905 if (SL->getCharByteWidth() == 1)
906 FmtStr = SL->getString();
907 else if (
auto EvaledFmtStr = SL->tryEvaluateString(Ctx))
908 FmtStr = *EvaledFmtStr;
910 goto CHECK_UNSAFE_PTR;
912 StringFormatStringHandler Handler(
Call, FmtArgIdx, UnsafeArg, Ctx);
915 Handler, FmtStr.begin(), FmtStr.end(), Ctx.
getLangOpts(),
923 llvm::make_range(
Call->arg_begin() + FmtArgIdx,
Call->arg_end()),
924 [&UnsafeArg](
const Expr *Arg) ->
bool {
925 if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg)) {
943 static std::unique_ptr<std::set<StringRef>> PredefinedNames =
nullptr;
944 if (!PredefinedNames)
946 std::make_unique<std::set<StringRef>, std::set<StringRef>>({
1018 auto *II =
Node.getIdentifier();
1024 II->getName(),
Node.getBuiltinID());
1027 if (PredefinedNames->find(Name) != PredefinedNames->end())
1030 std::string NameWCS = Name.str();
1031 size_t WcsPos = NameWCS.find(
"wcs");
1033 while (WcsPos != std::string::npos) {
1034 NameWCS[WcsPos++] =
's';
1035 NameWCS[WcsPos++] =
't';
1036 NameWCS[WcsPos++] =
'r';
1037 WcsPos = NameWCS.find(
"wcs", WcsPos);
1039 if (PredefinedNames->find(NameWCS) != PredefinedNames->end())
1043 return Name.ends_with(
"scanf");
1050 auto *II =
Node.getIdentifier();
1056 II->getName(),
Node.getBuiltinID());
1058 if (!Name.ends_with(
"printf"))
1060 return Name.starts_with(
"v");
1066 auto *II =
Node.getIdentifier();
1072 II->getName(),
Node.getBuiltinID());
1074 if (!Name.ends_with(
"printf") ||
1076 Name.starts_with(
"v"))
1079 StringRef Prefix = Name.drop_back(6);
1081 if (Prefix.ends_with(
"w"))
1082 Prefix = Prefix.drop_back(1);
1083 return Prefix ==
"s";
1090 auto *II =
Node.getIdentifier();
1096 II->getName(),
Node.getBuiltinID());
1098 if (!Name.ends_with(
"printf") || Name.starts_with(
"v"))
1101 StringRef Prefix = Name.drop_back(6);
1103 if (Prefix.ends_with(
"w"))
1104 Prefix = Prefix.drop_back(1);
1106 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
1114 MatchResult &Result, llvm::StringRef Tag) {
1118 assert(FD &&
"It should have been checked that FD is non-null.");
1136 const Expr *UnsafeArg;
1147 bool isKprintf =
false;
1148 const Expr *UnsafeArg;
1151 isKprintf = II->getName() ==
"kprintf";
1165 const Expr *UnsafeArg;
1176 for (
const auto *Arg :
Node.arguments())
1191 assert(FD &&
"It should have been checked that FD is non-null.");
1202 const Expr *Buf =
Node.getArg(0), *Size =
Node.getArg(1);
1206 !Size->getType()->isUnsignedIntegerType())
1235#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1238 Gadget(Kind K) : K(K) {}
1243 StringRef getDebugName()
const {
1248#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1250 llvm_unreachable(
"Unhandled Gadget::Kind enum");
1254 virtual bool isWarningGadget()
const = 0;
1262 virtual DeclUseList getClaimedVarUseSites()
const = 0;
1264 virtual ~Gadget() =
default;
1272class WarningGadget :
public Gadget {
1274 WarningGadget(Kind K) : Gadget(K) {}
1276 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1277 bool isWarningGadget() const final {
return true; }
1280 bool IsRelatedToDecl,
1290class FixableGadget :
public Gadget {
1292 FixableGadget(Kind K) : Gadget(K) {}
1294 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1295 bool isWarningGadget() const final {
return false; }
1300 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1301 return std::nullopt;
1310 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1311 getStrategyImplications()
const {
1312 return std::nullopt;
1318 return D !=
nullptr && isa<VarDecl>(
D);
1321using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1322using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1326class IncrementGadget :
public WarningGadget {
1327 static constexpr const char *
const OpTag =
"op";
1331 IncrementGadget(
const MatchResult &Result)
1332 : WarningGadget(
Kind::Increment),
1335 static bool classof(
const Gadget *G) {
1336 return G->getKind() == Kind::Increment;
1340 MatchResult &Result) {
1341 const auto *UO = dyn_cast<UnaryOperator>(S);
1351 bool IsRelatedToDecl,
1357 DeclUseList getClaimedVarUseSites()
const override {
1359 if (
const auto *DRE =
1361 Uses.push_back(DRE);
1364 return std::move(Uses);
1374class DecrementGadget :
public WarningGadget {
1375 static constexpr const char *
const OpTag =
"op";
1379 DecrementGadget(
const MatchResult &Result)
1380 : WarningGadget(
Kind::Decrement),
1383 static bool classof(
const Gadget *G) {
1384 return G->getKind() == Kind::Decrement;
1388 MatchResult &Result) {
1389 const auto *UO = dyn_cast<UnaryOperator>(S);
1399 bool IsRelatedToDecl,
1405 DeclUseList getClaimedVarUseSites()
const override {
1406 if (
const auto *DRE =
1421class ArraySubscriptGadget :
public WarningGadget {
1422 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1426 ArraySubscriptGadget(
const MatchResult &Result)
1430 static bool classof(
const Gadget *G) {
1431 return G->getKind() == Kind::ArraySubscript;
1435 MatchResult &Result) {
1436 const auto *ASE = dyn_cast<ArraySubscriptExpr>(S);
1442 const auto *Idx = dyn_cast<IntegerLiteral>(ASE->
getIdx());
1443 bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
1444 isa<ArrayInitIndexExpr>(ASE->
getIdx());
1452 bool IsRelatedToDecl,
1458 DeclUseList getClaimedVarUseSites()
const override {
1459 if (
const auto *DRE =
1476class PointerArithmeticGadget :
public WarningGadget {
1477 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1478 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1483 PointerArithmeticGadget(
const MatchResult &Result)
1484 : WarningGadget(
Kind::PointerArithmetic),
1486 Ptr(Result.getNodeAs<
Expr>(PointerArithmeticPointerTag)) {}
1488 static bool classof(
const Gadget *G) {
1489 return G->getKind() == Kind::PointerArithmetic;
1493 MatchResult &Result) {
1494 const auto *BO = dyn_cast<BinaryOperator>(S);
1497 const auto *LHS = BO->
getLHS();
1498 const auto *RHS = BO->
getRHS();
1503 RHS->getType()->isEnumeralType())) {
1511 (LHS->getType()->isIntegerType() || LHS->getType()->isEnumeralType())) {
1520 bool IsRelatedToDecl,
1526 DeclUseList getClaimedVarUseSites()
const override {
1542class SpanTwoParamConstructorGadget :
public WarningGadget {
1543 static constexpr const char *
const SpanTwoParamConstructorTag =
1544 "spanTwoParamConstructor";
1548 SpanTwoParamConstructorGadget(
const MatchResult &Result)
1549 : WarningGadget(
Kind::SpanTwoParamConstructor),
1552 static bool classof(
const Gadget *G) {
1553 return G->getKind() == Kind::SpanTwoParamConstructor;
1557 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1560 const auto *CDecl = CE->getConstructor();
1561 const auto *CRecordDecl = CDecl->getParent();
1562 auto HasTwoParamSpanCtorDecl =
1563 CRecordDecl->isInStdNamespace() &&
1564 CDecl->getDeclName().getAsString() ==
"span" && CE->getNumArgs() == 2;
1573 MatchResult &Result) {
1576 return matches(S, Ctx, Result);
1580 bool IsRelatedToDecl,
1586 DeclUseList getClaimedVarUseSites()
const override {
1589 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->
getArg(0))) {
1590 if (isa<VarDecl>(DRE->
getDecl()))
1603class PointerInitGadget :
public FixableGadget {
1605 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1606 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1611 PointerInitGadget(
const MatchResult &Result)
1612 : FixableGadget(
Kind::PointerInit),
1613 PtrInitLHS(Result.getNodeAs<
VarDecl>(PointerInitLHSTag)),
1614 PtrInitRHS(Result.getNodeAs<
DeclRefExpr>(PointerInitRHSTag)) {}
1616 static bool classof(
const Gadget *G) {
1617 return G->getKind() == Kind::PointerInit;
1622 const DeclStmt *DS = dyn_cast<DeclStmt>(S);
1631 const auto *DRE = dyn_cast<DeclRefExpr>(
Init->IgnoreImpCasts());
1632 if (!DRE || !
hasPointerType(*DRE) || !isSupportedVariable(*DRE)) {
1638 Results.emplace_back(std::move(R));
1642 virtual std::optional<FixItList>
1648 virtual DeclUseList getClaimedVarUseSites()
const override {
1649 return DeclUseList{PtrInitRHS};
1652 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1653 getStrategyImplications()
const override {
1654 return std::make_pair(PtrInitLHS, cast<VarDecl>(PtrInitRHS->
getDecl()));
1663class PtrToPtrAssignmentGadget :
public FixableGadget {
1665 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1666 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1671 PtrToPtrAssignmentGadget(
const MatchResult &Result)
1672 : FixableGadget(
Kind::PtrToPtrAssignment),
1673 PtrLHS(Result.getNodeAs<
DeclRefExpr>(PointerAssignLHSTag)),
1674 PtrRHS(Result.getNodeAs<
DeclRefExpr>(PointerAssignRHSTag)) {}
1676 static bool classof(
const Gadget *G) {
1677 return G->getKind() == Kind::PtrToPtrAssignment;
1682 size_t SizeBefore = Results.size();
1684 const auto *BO = dyn_cast<BinaryOperator>(S);
1685 if (!BO || BO->
getOpcode() != BO_Assign)
1688 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1690 !isSupportedVariable(*RHSRef)) {
1693 const auto *LHS = BO->
getLHS();
1694 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1696 !isSupportedVariable(*LHSRef)) {
1702 Results.emplace_back(std::move(R));
1704 return SizeBefore != Results.size();
1707 virtual std::optional<FixItList>
1711 virtual DeclUseList getClaimedVarUseSites()
const override {
1712 return DeclUseList{PtrLHS, PtrRHS};
1715 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1716 getStrategyImplications()
const override {
1717 return std::make_pair(cast<VarDecl>(PtrLHS->
getDecl()),
1718 cast<VarDecl>(PtrRHS->
getDecl()));
1727class CArrayToPtrAssignmentGadget :
public FixableGadget {
1729 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1730 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1735 CArrayToPtrAssignmentGadget(
const MatchResult &Result)
1736 : FixableGadget(
Kind::CArrayToPtrAssignment),
1737 PtrLHS(Result.getNodeAs<
DeclRefExpr>(PointerAssignLHSTag)),
1738 PtrRHS(Result.getNodeAs<
DeclRefExpr>(PointerAssignRHSTag)) {}
1740 static bool classof(
const Gadget *G) {
1741 return G->getKind() == Kind::CArrayToPtrAssignment;
1746 size_t SizeBefore = Results.size();
1748 const auto *BO = dyn_cast<BinaryOperator>(S);
1749 if (!BO || BO->
getOpcode() != BO_Assign)
1752 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1754 !isa<ConstantArrayType>(RHSRef->getType().getCanonicalType()) ||
1755 !isSupportedVariable(*RHSRef)) {
1758 const auto *LHS = BO->
getLHS();
1759 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1761 !isSupportedVariable(*LHSRef)) {
1767 Results.emplace_back(std::move(R));
1769 return SizeBefore != Results.size();
1772 virtual std::optional<FixItList>
1776 virtual DeclUseList getClaimedVarUseSites()
const override {
1777 return DeclUseList{PtrLHS, PtrRHS};
1780 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1781 getStrategyImplications()
const override {
1788class UnsafeBufferUsageAttrGadget :
public WarningGadget {
1789 constexpr static const char *
const OpTag =
"attr_expr";
1793 UnsafeBufferUsageAttrGadget(
const MatchResult &Result)
1794 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
1795 Op(Result.getNodeAs<
Expr>(OpTag)) {}
1797 static bool classof(
const Gadget *G) {
1798 return G->getKind() == Kind::UnsafeBufferUsageAttr;
1802 MatchResult &Result) {
1803 if (
auto *CE = dyn_cast<CallExpr>(S)) {
1804 if (CE->getDirectCallee() &&
1805 CE->getDirectCallee()->hasAttr<UnsafeBufferUsageAttr>()) {
1810 if (
auto *ME = dyn_cast<MemberExpr>(S)) {
1811 if (!isa<FieldDecl>(ME->getMemberDecl()))
1813 if (ME->getMemberDecl()->hasAttr<UnsafeBufferUsageAttr>()) {
1822 bool IsRelatedToDecl,
1828 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1836class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
1837 constexpr static const char *
const OpTag =
"cxx_construct_expr";
1841 UnsafeBufferUsageCtorAttrGadget(
const MatchResult &Result)
1842 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
1845 static bool classof(
const Gadget *G) {
1846 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
1850 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1851 if (!CE || !CE->getConstructor()->hasAttr<UnsafeBufferUsageAttr>())
1855 if (SpanTwoParamConstructorGadget::matches(CE, Ctx, Tmp))
1862 bool IsRelatedToDecl,
1868 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1877class DataInvocationGadget :
public WarningGadget {
1878 constexpr static const char *
const OpTag =
"data_invocation_expr";
1882 DataInvocationGadget(
const MatchResult &Result)
1883 : WarningGadget(
Kind::DataInvocation),
1886 static bool classof(
const Gadget *G) {
1887 return G->getKind() == Kind::DataInvocation;
1891 MatchResult &Result) {
1892 auto *CE = dyn_cast<ExplicitCastExpr>(S);
1895 for (
auto *Child : CE->children()) {
1896 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Child);
1897 MCE && isDataFunction(MCE)) {
1901 if (
auto *
Paren = dyn_cast<ParenExpr>(Child)) {
1902 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(
Paren->getSubExpr());
1903 MCE && isDataFunction(MCE)) {
1913 bool IsRelatedToDecl,
1919 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1926 if (!callee || !isa<CXXMethodDecl>(callee))
1928 auto *method = cast<CXXMethodDecl>(callee);
1929 if (method->getNameAsString() ==
"data" &&
1930 method->getParent()->isInStdNamespace() &&
1931 llvm::is_contained({SIZED_CONTAINER_OR_VIEW_LIST},
1932 method->getParent()->getName()))
1940class UnsafeLibcFunctionCallGadget :
public WarningGadget {
1942 const Expr *UnsafeArg =
nullptr;
1943 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
1945 constexpr static const char *
const UnsafeSprintfTag =
1946 "UnsafeLibcFunctionCall_sprintf";
1947 constexpr static const char *
const UnsafeSizedByTag =
1948 "UnsafeLibcFunctionCall_sized_by";
1949 constexpr static const char *
const UnsafeStringTag =
1950 "UnsafeLibcFunctionCall_string";
1951 constexpr static const char *
const UnsafeVaListTag =
1952 "UnsafeLibcFunctionCall_va_list";
1964 } WarnedFunKind = OTHERS;
1967 UnsafeLibcFunctionCallGadget(
const MatchResult &Result)
1968 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
1970 if (Result.getNodeAs<
Decl>(UnsafeSprintfTag))
1971 WarnedFunKind = SPRINTF;
1972 else if (
auto *
E = Result.getNodeAs<
Expr>(UnsafeStringTag)) {
1973 WarnedFunKind = STRING;
1975 }
else if (Result.getNodeAs<
CallExpr>(UnsafeSizedByTag)) {
1976 WarnedFunKind = SIZED_BY;
1977 UnsafeArg =
Call->getArg(0);
1978 }
else if (Result.getNodeAs<
Decl>(UnsafeVaListTag))
1979 WarnedFunKind = VA_LIST;
1984 MatchResult &Result) {
1987 auto *CE = dyn_cast<CallExpr>(S);
1988 if (!CE || !CE->getDirectCallee())
1990 const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
1994 bool IsGlobalAndNotInAnyNamespace =
1995 FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
1999 if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
2001 auto isSingleStringLiteralArg =
false;
2002 if (CE->getNumArgs() == 1) {
2003 isSingleStringLiteralArg =
2004 isa<clang::StringLiteral>(CE->getArg(0)->IgnoreParenImpCasts());
2006 if (!isSingleStringLiteralArg) {
2038 const Stmt *getBaseStmt()
const {
return Call; }
2043 bool IsRelatedToDecl,
2048 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2056class ULCArraySubscriptGadget :
public FixableGadget {
2058 static constexpr const char *
const ULCArraySubscriptTag =
2059 "ArraySubscriptUnderULC";
2063 ULCArraySubscriptGadget(
const MatchResult &Result)
2064 : FixableGadget(
Kind::ULCArraySubscript),
2066 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2069 static bool classof(
const Gadget *G) {
2070 return G->getKind() == Kind::ULCArraySubscript;
2075 size_t SizeBefore = Results.size();
2077 const auto *ASE = dyn_cast<ArraySubscriptExpr>(
E);
2083 !isSupportedVariable(*DRE))
2087 Results.emplace_back(std::move(R));
2089 return SizeBefore != Results.size();
2092 virtual std::optional<FixItList>
2096 virtual DeclUseList getClaimedVarUseSites()
const override {
2097 if (
const auto *DRE =
2098 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts())) {
2108class UPCStandalonePointerGadget :
public FixableGadget {
2110 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
2114 UPCStandalonePointerGadget(
const MatchResult &Result)
2115 : FixableGadget(
Kind::UPCStandalonePointer),
2117 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2120 static bool classof(
const Gadget *G) {
2121 return G->getKind() == Kind::UPCStandalonePointer;
2126 size_t SizeBefore = Results.size();
2128 auto *
E = dyn_cast<Expr>(S);
2133 !isSupportedVariable(*DRE))
2137 Results.emplace_back(std::move(R));
2139 return SizeBefore != Results.size();
2142 virtual std::optional<FixItList>
2146 virtual DeclUseList getClaimedVarUseSites()
const override {
return {
Node}; }
2149class PointerDereferenceGadget :
public FixableGadget {
2150 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2151 static constexpr const char *
const OperatorTag =
"op";
2157 PointerDereferenceGadget(
const MatchResult &Result)
2158 : FixableGadget(
Kind::PointerDereference),
2159 BaseDeclRefExpr(Result.getNodeAs<
DeclRefExpr>(BaseDeclRefExprTag)),
2162 static bool classof(
const Gadget *G) {
2163 return G->getKind() == Kind::PointerDereference;
2168 size_t SizeBefore = Results.size();
2170 const auto *UO = dyn_cast<UnaryOperator>(S);
2173 const auto *CE = dyn_cast<Expr>(UO->
getSubExpr());
2176 CE = CE->IgnoreParenImpCasts();
2177 const auto *DRE = dyn_cast<DeclRefExpr>(CE);
2178 if (!DRE || !isSupportedVariable(*DRE))
2183 Results.emplace_back(std::move(R));
2185 return SizeBefore != Results.size();
2188 DeclUseList getClaimedVarUseSites()
const override {
2189 return {BaseDeclRefExpr};
2192 virtual std::optional<FixItList>
2200class UPCAddressofArraySubscriptGadget :
public FixableGadget {
2202 static constexpr const char *
const UPCAddressofArraySubscriptTag =
2203 "AddressofArraySubscriptUnderUPC";
2207 UPCAddressofArraySubscriptGadget(
const MatchResult &Result)
2208 : FixableGadget(
Kind::ULCArraySubscript),
2210 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2213 static bool classof(
const Gadget *G) {
2214 return G->getKind() == Kind::UPCAddressofArraySubscript;
2219 size_t SizeBefore = Results.size();
2221 auto *
E = dyn_cast<Expr>(S);
2225 if (!UO || UO->
getOpcode() != UO_AddrOf)
2227 const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->
getSubExpr());
2232 if (!DRE || !isSupportedVariable(*DRE))
2236 Results.emplace_back(std::move(R));
2238 return SizeBefore != Results.size();
2241 virtual std::optional<FixItList>
2245 virtual DeclUseList getClaimedVarUseSites()
const override {
2246 const auto *ArraySubst = cast<ArraySubscriptExpr>(
Node->getSubExpr());
2248 cast<DeclRefExpr>(ArraySubst->getBase()->IgnoreParenImpCasts());
2258class DeclUseTracker {
2260 using DefMapTy = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
2263 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
2267 DeclUseTracker() =
default;
2268 DeclUseTracker(
const DeclUseTracker &) =
delete;
2269 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
2270 DeclUseTracker(DeclUseTracker &&) =
default;
2271 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
2274 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
2278 assert(Uses->count(DRE) &&
2279 "DRE not found or claimed by multiple matchers!");
2284 bool hasUnclaimedUses(
const VarDecl *VD)
const {
2286 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
2291 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
2293 for (
auto use : *Uses) {
2295 ReturnSet.insert(use);
2301 void discoverDecl(
const DeclStmt *DS) {
2303 if (
const auto *VD = dyn_cast<VarDecl>(
D)) {
2315 return Defs.lookup(VD);
2324 static constexpr const char *
const UPCPreIncrementTag =
2325 "PointerPreIncrementUnderUPC";
2330 : FixableGadget(Kind::UPCPreIncrement),
2332 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
2336 return G->getKind() == Kind::UPCPreIncrement;
2345 size_t SizeBefore = Results.size();
2347 auto *
E = dyn_cast<Expr>(S);
2351 if (!UO || UO->
getOpcode() != UO_PreInc)
2353 const auto *DRE = dyn_cast<DeclRefExpr>(UO->
getSubExpr());
2354 if (!DRE || !isSupportedVariable(*DRE))
2358 Results.emplace_back(std::move(R));
2360 return SizeBefore != Results.size();
2363 virtual std::optional<FixItList>
2368 return {dyn_cast<DeclRefExpr>(
Node->getSubExpr())};
2376 static constexpr const char *
const UUCAddAssignTag =
2377 "PointerAddAssignUnderUUC";
2378 static constexpr const char *
const OffsetTag =
"Offset";
2381 const Expr *Offset =
nullptr;
2385 : FixableGadget(Kind::UUCAddAssign),
2387 Offset(Result.getNodeAs<
Expr>(OffsetTag)) {
2388 assert(
Node !=
nullptr &&
"Expecting a non-null matching result");
2392 return G->getKind() == Kind::UUCAddAssign;
2397 size_t SizeBefore = Results.size();
2399 const auto *
E = dyn_cast<Expr>(S);
2403 if (!BO || BO->
getOpcode() != BO_AddAssign)
2405 const auto *DRE = dyn_cast<DeclRefExpr>(BO->
getLHS());
2411 Results.emplace_back(std::move(R));
2413 return SizeBefore != Results.size();
2416 virtual std::optional<FixItList>
2421 return {dyn_cast<DeclRefExpr>(
Node->getLHS())};
2428 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2429 static constexpr const char *
const DerefOpTag =
"DerefOp";
2430 static constexpr const char *
const AddOpTag =
"AddOp";
2431 static constexpr const char *
const OffsetTag =
"Offset";
2440 : FixableGadget(Kind::DerefSimplePtrArithFixable),
2441 BaseDeclRefExpr(Result.getNodeAs<
DeclRefExpr>(BaseDeclRefExprTag)),
2452 if (!DRE || !isSupportedVariable(*DRE))
2457 const auto IsPlusOverPtrAndInteger = [&IsPtr](
const Expr *
E,
2459 const auto *BO = dyn_cast<BinaryOperator>(
E);
2463 const auto *LHS = BO->
getLHS();
2464 const auto *RHS = BO->
getRHS();
2465 if (isa<IntegerLiteral>(RHS) && IsPtr(LHS, R)) {
2470 if (isa<IntegerLiteral>(LHS) && IsPtr(RHS, R)) {
2477 size_t SizeBefore = Results.size();
2478 const auto InnerMatcher = [&IsPlusOverPtrAndInteger,
2479 &Results](
const Expr *
E) {
2480 const auto *UO = dyn_cast<UnaryOperator>(
E);
2486 if (IsPlusOverPtrAndInteger(Operand, R)) {
2488 Results.emplace_back(std::move(R));
2492 return SizeBefore != Results.size();
2495 virtual std::optional<FixItList>
2502 return {BaseDeclRefExpr};
2510 : WarningGadgets(WarningGadgets) {}
2519#define WARNING_GADGET(name) \
2520 if (name##Gadget::matches(S, Ctx, Result) && \
2521 notInSafeBufferOptOut(*S, &Handler)) { \
2522 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2525#define WARNING_OPTIONAL_GADGET(name) \
2526 if (name##Gadget::matches(S, Ctx, &Handler, Result) && \
2527 notInSafeBufferOptOut(*S, &Handler)) { \
2528 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2531#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2536 WarningGadgetList &WarningGadgets;
2543 DeclUseTracker &Tracker)
2544 : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
2548 bool matchFound =
false;
2555#define FIXABLE_GADGET(name) \
2556 if (name##Gadget::matches(S, Results)) { \
2557 for (const auto &R : Results) { \
2558 FixableGadgets.push_back(std::make_unique<name##Gadget>(R)); \
2559 matchFound = true; \
2563#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2566 if (
auto *DRE = findDeclRefExpr(S); DRE) {
2567 Tracker.discoverUse(DRE);
2573 if (
auto *DS = findDeclStmt(S); DS) {
2574 Tracker.discoverDecl(DS);
2582 const auto *DRE = dyn_cast<DeclRefExpr>(S);
2586 if (!
D || (!isa<VarDecl>(
D) && !isa<BindingDecl>(
D)))
2591 const auto *DS = dyn_cast<DeclStmt>(S);
2596 FixableGadgetList &FixableGadgets;
2597 DeclUseTracker &Tracker;
2603 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2604 WarningGadgetList &WarningGadgets,
2605 DeclUseTracker &Tracker) {
2608 if (EmitSuggestions) {
2617 return N1->getBeginLoc().getRawEncoding() <
2618 N2->getBeginLoc().getRawEncoding();
2628 const Expr *UnsafeArg =
nullptr)
override {}
2650 FixableGadgetList FixableGadgets;
2651 WarningGadgetList WarningGadgets;
2652 DeclUseTracker Tracker;
2653 MockReporter IgnoreHandler;
2656 FixableGadgets, WarningGadgets, Tracker);
2658 std::set<const Expr *> Result;
2659 for (
auto &G : WarningGadgets) {
2660 for (
const Expr *
E : G->getUnsafePtrs()) {
2669 std::map<const VarDecl *, std::set<const WarningGadget *>,
2683 for (
auto &G : AllUnsafeOperations) {
2684 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
2686 bool AssociatedWithVarDecl =
false;
2687 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
2688 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2689 result.
byVar[VD].insert(G.get());
2690 AssociatedWithVarDecl =
true;
2694 if (!AssociatedWithVarDecl) {
2695 result.
noVar.push_back(G.get());
2703 std::map<const VarDecl *, std::set<const FixableGadget *>,
2713 for (
auto &F : AllFixableOperations) {
2714 DeclUseList DREs = F->getClaimedVarUseSites();
2717 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2718 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
2722 return FixablesForUnsafeVars;
2729 std::vector<const FixItHint *> All;
2733 std::sort(All.begin(), All.end(),
2735 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
2736 H2->RemoveRange.getBegin());
2744 Hint->RemoveRange.getBegin())) {
2756std::optional<FixItList>
2757PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2758 const auto *LeftVD = cast<VarDecl>(PtrLHS->
getDecl());
2759 const auto *RightVD = cast<VarDecl>(PtrRHS->
getDecl());
2760 switch (S.lookup(LeftVD)) {
2761 case FixitStrategy::Kind::Span:
2762 if (S.lookup(RightVD) == FixitStrategy::Kind::Span)
2764 return std::nullopt;
2765 case FixitStrategy::Kind::Wontfix:
2766 return std::nullopt;
2767 case FixitStrategy::Kind::Iterator:
2768 case FixitStrategy::Kind::Array:
2769 return std::nullopt;
2770 case FixitStrategy::Kind::Vector:
2771 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2773 return std::nullopt;
2780std::optional<FixItList>
2781CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2782 const auto *LeftVD = cast<VarDecl>(PtrLHS->
getDecl());
2783 const auto *RightVD = cast<VarDecl>(PtrRHS->
getDecl());
2800 if (S.lookup(LeftVD) == FixitStrategy::Kind::Span) {
2801 if (S.lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
2804 }
else if (S.lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
2805 if (S.lookup(RightVD) == FixitStrategy::Kind::Array) {
2809 return std::nullopt;
2812std::optional<FixItList>
2814 const auto *LeftVD = PtrInitLHS;
2815 const auto *RightVD = cast<VarDecl>(PtrInitRHS->
getDecl());
2816 switch (S.lookup(LeftVD)) {
2817 case FixitStrategy::Kind::Span:
2818 if (S.lookup(RightVD) == FixitStrategy::Kind::Span)
2820 return std::nullopt;
2821 case FixitStrategy::Kind::Wontfix:
2822 return std::nullopt;
2823 case FixitStrategy::Kind::Iterator:
2824 case FixitStrategy::Kind::Array:
2825 return std::nullopt;
2826 case FixitStrategy::Kind::Vector:
2827 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2829 return std::nullopt;
2835 if (ConstVal->isNegative())
2842std::optional<FixItList>
2843ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2844 if (
const auto *DRE =
2845 dyn_cast<DeclRefExpr>(
Node->getBase()->IgnoreImpCasts()))
2846 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2847 switch (S.lookup(VD)) {
2848 case FixitStrategy::Kind::Span: {
2855 return std::nullopt;
2859 case FixitStrategy::Kind::Array:
2861 case FixitStrategy::Kind::Wontfix:
2862 case FixitStrategy::Kind::Iterator:
2863 case FixitStrategy::Kind::Vector:
2864 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2867 return std::nullopt;
2870static std::optional<FixItList>
2873std::optional<FixItList>
2874UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2875 auto DREs = getClaimedVarUseSites();
2876 const auto *VD = cast<VarDecl>(DREs.front()->getDecl());
2878 switch (S.lookup(VD)) {
2879 case FixitStrategy::Kind::Span:
2881 case FixitStrategy::Kind::Wontfix:
2882 case FixitStrategy::Kind::Iterator:
2883 case FixitStrategy::Kind::Array:
2884 return std::nullopt;
2885 case FixitStrategy::Kind::Vector:
2886 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2888 return std::nullopt;
2893 static const char *
const EOL =
"\n";
2900 std::string
s = std::string(
"<# ");
2901 s += HintTextToUser;
2907template <
typename NodeTy>
2908static std::optional<SourceLocation>
2911 if (
unsigned TkLen =
2918 return std::nullopt;
2931 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
2932 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
2933 VD->getBeginLoc())) &&
2934 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
2935 At->getRange().getBegin()));
2939 AttrRangeOverlapping;
2981 std::optional<Qualifiers> Quals = std::nullopt) {
2982 const char *
const SpanOpen =
"std::span<";
2985 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
2986 return SpanOpen + EltTyText.str() +
'>';
2989std::optional<FixItList>
2991 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->
getDecl());
2993 if (VD &&
s.lookup(VD) == FixitStrategy::Kind::Span) {
2997 if (ConstVal->isNegative())
2998 return std::nullopt;
3026 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
3028 return std::nullopt;
3033 std::optional<SourceLocation> AddOpLocation =
3035 std::optional<SourceLocation> DerefOpLocation =
3038 if (!AddOpLocation || !DerefOpLocation)
3039 return std::nullopt;
3049 return std::nullopt;
3052std::optional<FixItList>
3053PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
3055 switch (S.lookup(VD)) {
3056 case FixitStrategy::Kind::Span: {
3064 if (
auto LocPastOperand =
3071 case FixitStrategy::Kind::Iterator:
3072 case FixitStrategy::Kind::Array:
3073 return std::nullopt;
3074 case FixitStrategy::Kind::Vector:
3075 llvm_unreachable(
"FixitStrategy not implemented yet!");
3076 case FixitStrategy::Kind::Wontfix:
3077 llvm_unreachable(
"Invalid strategy!");
3080 return std::nullopt;
3087 std::optional<SourceLocation> EndOfOperand =
3093 return std::nullopt;
3098std::optional<FixItList>
3099UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
3100 const auto VD = cast<VarDecl>(
Node->getDecl());
3101 switch (S.lookup(VD)) {
3102 case FixitStrategy::Kind::Array:
3103 case FixitStrategy::Kind::Span: {
3108 case FixitStrategy::Kind::Wontfix:
3109 case FixitStrategy::Kind::Iterator:
3110 return std::nullopt;
3111 case FixitStrategy::Kind::Vector:
3112 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3115 return std::nullopt;
3120static std::optional<FixItList>
3122 const auto *ArraySub = cast<ArraySubscriptExpr>(
Node->getSubExpr());
3123 const auto *DRE = cast<DeclRefExpr>(ArraySub->getBase()->IgnoreImpCasts());
3127 const Expr *Idx = ArraySub->getIdx();
3130 std::stringstream SS;
3131 bool IdxIsLitZero =
false;
3134 if ((*ICE).isZero())
3135 IdxIsLitZero =
true;
3136 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
3138 return std::nullopt;
3142 SS << (*DreString).str() <<
".data()";
3144 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
3146 return std::nullopt;
3148 SS <<
"&" << (*DreString).str() <<
".data()"
3149 <<
"[" << (*IndexString).str() <<
"]";
3155std::optional<FixItList>
3159 if (DREs.size() != 1)
3160 return std::nullopt;
3162 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3163 if (S.lookup(VD) == FixitStrategy::Kind::Span) {
3167 StringRef varName = VD->
getName();
3171 return std::nullopt;
3176 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
3180 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
3182 if (!AddAssignLocation)
3183 return std::nullopt;
3194 return std::nullopt;
3197std::optional<FixItList>
3201 if (DREs.size() != 1)
3202 return std::nullopt;
3204 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3205 if (S.lookup(VD) == FixitStrategy::Kind::Span) {
3207 std::stringstream SS;
3208 StringRef varName = VD->
getName();
3212 SS <<
"(" << varName.data() <<
" = " << varName.data()
3213 <<
".subspan(1)).data()";
3214 std::optional<SourceLocation> PreIncLocation =
3216 if (!PreIncLocation)
3217 return std::nullopt;
3224 return std::nullopt;
3242static std::optional<FixItList>
3244 const StringRef UserFillPlaceHolder) {
3252 if (
Init->isNullPointerConstant(
3257 NPC_ValueDependentIsNotNull)) {
3258 std::optional<SourceLocation> InitLocation =
3261 return std::nullopt;
3269 std::string ExtentText = UserFillPlaceHolder.data();
3270 StringRef One =
"1";
3275 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
3280 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
3281 if (!Ext->HasSideEffects(Ctx)) {
3282 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
3284 return std::nullopt;
3285 ExtentText = *ExtentString;
3287 }
else if (!CxxNew->isArray())
3299 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
3300 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
3301 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
3308 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
3311 return std::nullopt;
3313 StrBuffer.append(
", ");
3314 StrBuffer.append(ExtentText);
3315 StrBuffer.append(
"}");
3321#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
3322 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
3323 "failed to produce fixit for declaration '" + \
3324 (D)->getNameAsString() + "'" + (Msg))
3326#define DEBUG_NOTE_DECL_FAIL(D, Msg)
3332static std::optional<std::string>
3336 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3341 return std::nullopt;
3343 std::string SpanTyText =
"std::span<";
3345 SpanTyText.append(*PteTyText);
3347 if (PteTyQualifiers) {
3348 SpanTyText.append(
" ");
3349 SpanTyText.append(PteTyQualifiers->getAsString());
3351 SpanTyText.append(
">");
3370 const StringRef UserFillPlaceHolder,
3384 std::stringstream SS;
3389 std::optional<FixItList> InitFixIts =
3393 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
3394 std::make_move_iterator(InitFixIts->end()));
3401 if (!EndLocForReplacement.
isValid()) {
3451static std::optional<FixItList>
3457 return std::nullopt;
3462 std::vector<std::string> NewTysTexts(NumParms);
3463 std::vector<bool> ParmsMask(NumParms,
false);
3464 bool AtLeastOneParmToFix =
false;
3466 for (
unsigned i = 0; i < NumParms; i++) {
3469 if (S.lookup(PVD) == FixitStrategy::Kind::Wontfix)
3471 if (S.lookup(PVD) != FixitStrategy::Kind::Span)
3473 return std::nullopt;
3475 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3476 std::optional<std::string> PteTyText =
3481 return std::nullopt;
3485 ParmsMask[i] =
true;
3486 AtLeastOneParmToFix =
true;
3488 if (!AtLeastOneParmToFix)
3495 const auto NewOverloadSignatureCreator =
3496 [&
SM, &LangOpts, &NewTysTexts,
3497 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3498 std::stringstream SS;
3506 SS << Prefix->str();
3508 return std::nullopt;
3512 for (
unsigned i = 0; i < NumParms; i++) {
3520 SS << NewTysTexts[i];
3523 SS <<
' ' << II->
getName().str();
3524 }
else if (
auto ParmTypeText =
3528 SS << ParmTypeText->str();
3530 return std::nullopt;
3531 if (i != NumParms - 1)
3540 const auto OldOverloadDefCreator =
3541 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3542 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3543 std::stringstream SS;
3551 << FDPrefix->str() <<
"{";
3553 return std::nullopt;
3556 SS <<
"return " << FunQualName->str() <<
"(";
3558 return std::nullopt;
3562 for (
unsigned i = 0; i < NumParms; i++) {
3571 return std::nullopt;
3578 if (i != NumParms - 1)
3589 std::optional<SourceLocation>
Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3593 if (FReDecl->isThisDeclarationADefinition()) {
3594 assert(FReDecl == FD &&
"inconsistent function definition");
3597 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3603 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3606 FReDecl->getBeginLoc(),
" ")));
3609 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3631 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3647 std::stringstream SS;
3650 if (PteTyQualifiers)
3659 SS <<
' ' << PVDNameText->str();
3665 const DeclUseTracker &Tracker,
3668 const DeclStmt *DS = Tracker.lookupDecl(VD);
3671 " : variables declared this way not implemented yet");
3695 const QualType &ArrayEltT = CAT->getElementType();
3696 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
3705 auto MaybeElemTypeTxt =
3708 if (!MaybeElemTypeTxt)
3710 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
3715 while (NextTok && !NextTok->is(tok::l_square) &&
3728 if (!MaybeArraySizeTxt)
3730 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
3731 if (ArraySizeTxt.empty()) {
3742 std::optional<StringRef> IdentText =
3751 llvm::raw_svector_ostream OS(Replacement);
3752 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
3753 << IdentText->str();
3763 const DeclUseTracker &Tracker,
3766 const DeclStmt *DS = Tracker.lookupDecl(VD);
3767 assert(DS &&
"Fixing non-local variables not implemented yet!");
3786 const DeclUseTracker &Tracker,
ASTContext &Ctx,
3788 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
3789 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
3790 if (!FD || FD !=
D) {
3801 if (FD->isMain() || FD->isConstexpr() ||
3802 FD->getTemplatedKind() != FunctionDecl::TemplatedKind::TK_NonTemplate ||
3805 isa<CXXMethodDecl>(FD) ||
3807 (FD->hasBody() && isa<CXXTryStmt>(FD->getBody())) ||
3808 FD->isOverloadedOperator()) {
3815 case FixitStrategy::Kind::Span: {
3817 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
3826 case FixitStrategy::Kind::Array: {
3833 case FixitStrategy::Kind::Iterator:
3834 case FixitStrategy::Kind::Vector:
3835 llvm_unreachable(
"FixitStrategy not implemented yet!");
3836 case FixitStrategy::Kind::Wontfix:
3837 llvm_unreachable(
"Invalid strategy!");
3839 llvm_unreachable(
"Unknown strategy!");
3847 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
3858 return isa<ParmVarDecl>(VD) &&
3866 std::map<const VarDecl *, FixItList> &FixItsForVariable,
3871 for (
const auto &[VD, Ignore] : FixItsForVariable) {
3873 if (llvm::any_of(Grp,
3874 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
3875 return !FixItsForVariable.count(GrpMember);
3880 ToErase.push_back(
Member);
3883 for (
auto *VarToErase : ToErase)
3884 FixItsForVariable.erase(VarToErase);
3895 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
3899 FixItList FixItsSharedByParms{};
3901 std::optional<FixItList> OverloadFixes =
3904 if (OverloadFixes) {
3905 FixItsSharedByParms.append(*OverloadFixes);
3911 FixItsForVariable.erase(
Member);
3913 return FixItsSharedByParms;
3917static std::map<const VarDecl *, FixItList>
3926 std::map<const VarDecl *, FixItList> FixItsForVariable;
3931 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
3932 FixItsForVariable[VD] =
3933 fixVariable(VD, S.lookup(VD),
D, Tracker, Ctx, Handler);
3936 if (FixItsForVariable[VD].empty()) {
3937 FixItsForVariable.erase(VD);
3940 for (
const auto &F : Fixables) {
3941 std::optional<FixItList> Fixits = F->getFixits(S);
3944 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
3945 Fixits->begin(), Fixits->end());
3950 VD, F->getSourceLoc(),
3951 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
3954 FixItsForVariable.erase(VD);
3973 FixItList FixItsSharedByParms{};
3975 if (
auto *FD = dyn_cast<FunctionDecl>(
D))
3977 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
3981 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
3984 for (
auto &[Var, Ignore] : FixItsForVariable) {
3985 bool AnyParm =
false;
3986 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
3988 for (
const VarDecl *GrpMate : VarGroupForVD) {
3991 if (FixItsForVariable.count(GrpMate))
3992 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
3996 assert(!FixItsSharedByParms.empty() &&
3997 "Should not try to fix a parameter that does not belong to a "
3999 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
4006 for (
auto Iter = FinalFixItsForVariable.begin();
4007 Iter != FinalFixItsForVariable.end();)
4010 Iter = FinalFixItsForVariable.erase(
Iter);
4013 return FinalFixItsForVariable;
4016template <
typename VarDeclIterTy>
4020 for (
const VarDecl *VD : UnsafeVars) {
4022 S.set(VD, FixitStrategy::Kind::Array);
4024 S.set(VD, FixitStrategy::Kind::Span);
4031 const std::vector<VarGrpTy> Groups;
4032 const std::map<const VarDecl *, unsigned> &VarGrpMap;
4033 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
4037 const std::vector<VarGrpTy> &Groups,
4038 const std::map<const VarDecl *, unsigned> &VarGrpMap,
4039 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
4040 : Groups(Groups), VarGrpMap(VarGrpMap),
4041 GrpsUnionForParms(GrpsUnionForParms) {}
4044 if (GrpsUnionForParms.contains(Var)) {
4047 return GrpsUnionForParms.getArrayRef();
4052 auto It = VarGrpMap.find(Var);
4054 if (It == VarGrpMap.end())
4056 return Groups[It->second];
4060 return GrpsUnionForParms.getArrayRef();
4065 WarningGadgetList WarningGadgets,
4066 DeclUseTracker Tracker,
4068 bool EmitSuggestions) {
4069 if (!EmitSuggestions) {
4073 for (
const auto &G : WarningGadgets) {
4074 G->handleUnsafeOperation(Handler,
false,
4080 assert(FixableGadgets.empty() &&
4081 "Fixable gadgets found but suggestions not requested!");
4087 if (!WarningGadgets.empty()) {
4091 for (
const auto &G : FixableGadgets) {
4092 for (
const auto *DRE : G->getClaimedVarUseSites()) {
4093 Tracker.claimUse(DRE);
4109 if (WarningGadgets.empty())
4117 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
4120 for (
auto it = FixablesForAllVars.
byVar.cbegin();
4121 it != FixablesForAllVars.
byVar.cend();) {
4123 if ((!it->first->isLocalVarDecl() && !isa<ParmVarDecl>(it->first))) {
4126 (
"failed to produce fixit for '" +
4127 it->first->getNameAsString() +
4128 "' : neither local nor a parameter"));
4130 it = FixablesForAllVars.
byVar.erase(it);
4131 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
4134 (
"failed to produce fixit for '" +
4135 it->first->getNameAsString() +
4136 "' : has a reference type"));
4138 it = FixablesForAllVars.
byVar.erase(it);
4139 }
else if (Tracker.hasUnclaimedUses(it->first)) {
4140 it = FixablesForAllVars.
byVar.erase(it);
4141 }
else if (it->first->isInitCapture()) {
4144 (
"failed to produce fixit for '" +
4145 it->first->getNameAsString() +
4146 "' : init capture"));
4148 it = FixablesForAllVars.
byVar.erase(it);
4155 for (
const auto &it : UnsafeOps.
byVar) {
4156 const VarDecl *
const UnsafeVD = it.first;
4157 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
4158 if (UnclaimedDREs.empty())
4162 std::string UnclaimedUseTrace =
4167 (
"failed to produce fixit for '" + UnfixedVDName +
4168 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
4169 UnclaimedUseTrace));
4176 llvm::DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
4177 DepMapTy DependenciesMap{};
4178 DepMapTy PtrAssignmentGraph{};
4180 for (
const auto &it : FixablesForAllVars.
byVar) {
4181 for (
const FixableGadget *fixable : it.second) {
4182 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
4183 fixable->getStrategyImplications();
4185 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
4186 PtrAssignmentGraph[Impl.first].insert(Impl.second);
4208 std::set<const VarDecl *> VisitedVarsDirected{};
4209 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4210 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
4212 std::queue<const VarDecl *> QueueDirected{};
4213 QueueDirected.push(Var);
4214 while (!QueueDirected.empty()) {
4215 const VarDecl *CurrentVar = QueueDirected.front();
4216 QueueDirected.pop();
4217 VisitedVarsDirected.insert(CurrentVar);
4218 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
4219 for (
const VarDecl *Adj : AdjacentNodes) {
4220 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
4221 QueueDirected.push(Adj);
4223 DependenciesMap[Var].insert(Adj);
4224 DependenciesMap[Adj].insert(Var);
4231 std::vector<VarGrpTy> Groups;
4235 std::map<const VarDecl *, unsigned> VarGrpMap;
4237 llvm::SetVector<const VarDecl *>
4242 std::set<const VarDecl *> VisitedVars{};
4243 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4244 if (VisitedVars.find(Var) == VisitedVars.end()) {
4245 VarGrpTy &VarGroup = Groups.emplace_back();
4246 std::queue<const VarDecl *> Queue{};
4249 while (!Queue.empty()) {
4250 const VarDecl *CurrentVar = Queue.front();
4252 VisitedVars.insert(CurrentVar);
4253 VarGroup.push_back(CurrentVar);
4254 auto AdjacentNodes = DependenciesMap[CurrentVar];
4255 for (
const VarDecl *Adj : AdjacentNodes) {
4256 if (VisitedVars.find(Adj) == VisitedVars.end()) {
4262 bool HasParm =
false;
4263 unsigned GrpIdx = Groups.size() - 1;
4265 for (
const VarDecl *
V : VarGroup) {
4266 VarGrpMap[
V] = GrpIdx;
4271 GrpsUnionForParms.insert_range(VarGroup);
4293 for (
auto I = FixablesForAllVars.
byVar.begin();
4294 I != FixablesForAllVars.
byVar.end();) {
4296 if (!VisitedVars.count((*I).first)) {
4298 I = FixablesForAllVars.
byVar.erase(I);
4306 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
4308 return FixablesForAllVars.
byVar.count(
V);
4312 if (isa<NamedDecl>(
D))
4315 FixItsForVariableGroup =
4317 Tracker, Handler, VarGrpMgr);
4319 for (
const auto &G : UnsafeOps.
noVar) {
4320 G->handleUnsafeOperation(Handler,
false,
4324 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
4325 auto FixItsIt = FixItsForVariableGroup.find(VD);
4327 FixItsIt != FixItsForVariableGroup.end()
4328 ? std::move(FixItsIt->second)
4331 for (
const auto &G : WarningGadgets) {
4332 G->handleUnsafeOperation(Handler,
true,
4340 bool EmitSuggestions) {
4349 if (
const auto *FD = dyn_cast<FunctionDecl>(
D)) {
4353 if (
const auto *MD = dyn_cast<CXXMethodDecl>(
D)) {
4354 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
4359 if (FReDecl->isExternC()) {
4362 EmitSuggestions =
false;
4367 Stmts.push_back(FD->getBody());
4369 if (
const auto *ID = dyn_cast<CXXConstructorDecl>(
D)) {
4371 Stmts.push_back(CI->getInit());
4374 }
else if (isa<BlockDecl>(
D) || isa<ObjCMethodDecl>(
D)) {
4378 assert(!Stmts.empty());
4380 FixableGadgetList FixableGadgets;
4381 WarningGadgetList WarningGadgets;
4382 DeclUseTracker Tracker;
4383 for (
Stmt *S : Stmts) {
4385 WarningGadgets, Tracker);
4387 applyGadgets(
D, std::move(FixableGadgets), std::move(WarningGadgets),
4388 std::move(Tracker), Handler, EmitSuggestions);
Defines the clang::ASTContext interface.
BoundNodesTreeBuilder Nodes
static Decl::Kind getKind(const Decl *D)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
static const Decl * getCanonicalDecl(const Decl *D)
llvm::MachO::Target Target
Defines the clang::Preprocessor interface.
MatchFinder::MatchResult MatchResult
Defines the clang::SourceLocation class and associated facilities.
static QualType getPointeeType(const MemRegion *R)
C Language Family Type Representation.
static bool ignoreUnsafeLibcCall(const ASTContext &Ctx, const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
static void findStmtsInUnspecifiedLvalueContext(const Stmt *S, const llvm::function_ref< void(const Expr *)> OnResult)
static bool isSafeArraySubscript(const ArraySubscriptExpr &Node, const ASTContext &Ctx)
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 bool ignoreUnsafeBufferInContainer(const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
static WarningGadgetSets groupWarningGadgetsByVar(const WarningGadgetList &AllUnsafeOperations)
static bool hasArrayType(const Expr &E)
static StringRef getEndOfLine()
static bool notInSafeBufferOptOut(const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
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 bool areEqualIntegralBinaryOperators(const BinaryOperator *E1, const Expr *E2_LHS, BinaryOperatorKind BOP, const Expr *E2_RHS, ASTContext &Ctx)
static bool hasPointerType(const Expr &E)
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)
static bool isSafeSpanTwoParamConstruct(const CXXConstructExpr &Node, ASTContext &Ctx)
static FixItList fixVarDeclWithArray(const VarDecl *D, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
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 FixitStrategy getNaiveStrategy(llvm::iterator_range< VarDeclIterTy > UnsafeVars)
static std::optional< std::string > createSpanTypeForVarDecl(const VarDecl *VD, const ASTContext &Ctx)
static bool hasConflictingOverload(const FunctionDecl *FD)
static void findStmtsInUnspecifiedPointerContext(const Stmt *S, llvm::function_ref< void(const Stmt *)> InnerMatcher)
static bool isNonNegativeIntegerExpr(const Expr *Expr, const VarDecl *VD, const ASTContext &Ctx)
static bool overlapWithMacro(const FixItList &FixIts)
static void forEachDescendantStmt(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, FastMatcher &Matcher)
static bool hasUnsupportedSpecifiers(const VarDecl *VD, const SourceManager &SM)
#define DEBUG_NOTE_DECL_FAIL(D, Msg)
static void applyGadgets(const Decl *D, FixableGadgetList FixableGadgets, WarningGadgetList WarningGadgets, DeclUseTracker Tracker, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
static bool areEqualIntegers(const Expr *E1, const Expr *E2, ASTContext &Ctx)
static void findGadgets(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, bool EmitSuggestions, FixableGadgetList &FixableGadgets, WarningGadgetList &WarningGadgets, DeclUseTracker &Tracker)
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 bool isPtrBufferSafe(const Expr *Ptr, const Expr *Size, ASTContext &Ctx)
static void forEachDescendantEvaluatedStmt(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, FastMatcher &Matcher)
static void findStmtsInUnspecifiedUntypedContext(const Stmt *S, llvm::function_ref< void(const Stmt *)> InnerMatcher)
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)
#define SIZED_CONTAINER_OR_VIEW_LIST
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
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
DerefSimplePtrArithFixableGadget(const MatchResult &Result)
SourceLocation getSourceLoc() const override
virtual DeclUseList getClaimedVarUseSites() const final
FixableGadgetMatcher(FixableGadgetList &FixableGadgets, DeclUseTracker &Tracker)
bool matches(const DynTypedNode &DynNode, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler) override
bool TraverseCXXTypeidExpr(CXXTypeidExpr *Node) override
MatchDescendantVisitor(ASTContext &Context, FastMatcher &Matcher, bool FindAll, bool ignoreUnevaluatedContext, const UnsafeBufferUsageHandler &NewHandler)
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc Node, bool TraverseQualifier) override
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc Node, bool TraverseQualifier) override
bool TraverseGenericSelectionExpr(GenericSelectionExpr *Node) override
bool TraverseDecl(Decl *Node) override
bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) override
bool findMatch(const DynTypedNode &DynNode)
bool TraverseCXXDefaultInitExpr(CXXDefaultInitExpr *Node) override
bool TraverseCXXNoexceptExpr(CXXNoexceptExpr *Node) override
bool TraverseStmt(Stmt *Node) override
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
SourceLocation getSourceLoc() const override
virtual DeclUseList getClaimedVarUseSites() const override
UPCPreIncrementGadget(const MatchResult &Result)
static bool classof(const Gadget *G)
static bool classof(const Gadget *G)
UUCAddAssignGadget(const MatchResult &Result)
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
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,...
bool matches(const DynTypedNode &DynNode, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler) override
WarningGadgetMatcher(WarningGadgetList &WarningGadgets)
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
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
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 call to a member function that may be written either with member call syntax (e....
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]).
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
static const char * getCastKindName(CastKind CK)
Represents a character-granular source range.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getEnd() const
bool isOne() const
isOne - Test whether the quantity equals one.
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
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.
const Decl * getSingleDecl() const
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...
DeclContext * getDeclContext()
SourceLocation getBeginLoc() const LLVM_READONLY
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
SourceLocation getBeginLoc() const LLVM_READONLY
NestedNameSpecifierLoc getQualifierLoc() const
Retrieve the nested-name-specifier (with source-location information) that qualifies the name of this...
NestedNameSpecifier getQualifier() const
Retrieve the nested-name-specifier that qualifies the name of this declaration, if it was present in ...
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
const DynTypedNode * begin() const
A dynamically typed AST node container.
const T * get() const
Retrieve the stored node as type T.
static DynTypedNode create(const T &Node)
Creates a DynTypedNode from Node.
SourceRange getSourceRange(bool IncludeQualifier=false) const
For nodes which represent textual entities in the source code, return their SourceRange.
Recursive AST visitor that supports extension via dynamic dispatch.
virtual bool TraverseDecl(MaybeConst< Decl > *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
bool ShouldVisitTemplateInstantiations
Whether this visitor should recurse into template instantiations.
bool ShouldVisitImplicitCode
Whether this visitor should recurse into implicit code, e.g.
virtual bool TraverseStmt(MaybeConst< Stmt > *S)
Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...
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 * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
NullPointerConstantValueDependence
Enumeration used to describe how isNullPointerConstant() should cope with value-dependent expressions...
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
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.
A simple pair of identifier info and location.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
static IntegerLiteral * Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l)
Returns a new integer literal with value 'V' and type 'type'.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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.
A single parameter index whose accessors require each use to make explicit the parameter index encodi...
bool isValid() const
Is this parameter index valid?
unsigned getASTIndex() const
Get the parameter index as it would normally be encoded at the AST level of representation: zero-orig...
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.
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.
The base class of the type hierarchy.
bool isConstantSizeType() const
Return true if this is not a variable sized type, according to the rules of C99 6....
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 isAnyCharacterType() const
Determine whether this type is any of the built-in character types.
bool isWideCharType() const
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
bool isAnyPointerType() const
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
static bool isIncrementOp(Opcode Op)
SourceLocation getBeginLoc() const LLVM_READONLY
static bool isDecrementOp(Opcode Op)
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 bool isSafeBufferOptOut(const SourceLocation &Loc) const =0
virtual bool ignoreUnsafeBufferInContainer(const SourceLocation &Loc) 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 bool ignoreUnsafeBufferInLibcCall(const SourceLocation &Loc) const =0
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.
const Expr * getAnyInitializer() const
Get the initializer for this variable, no matter which declaration it is attached to.
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,...
void matchEachArgumentWithParamType(const CallExpr &Node, llvm::function_ref< void(QualType, const Expr *)> OnParamAndArg)
bool anyConflict(const llvm::SmallVectorImpl< FixItHint > &FixIts, const SourceManager &SM)
bool Call(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
bool matches(const til::SExpr *E1, const til::SExpr *E2)
The JSON file list parser is used to communicate input to InstallAPI.
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
SourceLocation getVarDeclIdentifierLoc(const DeclaratorDecl *VD)
std::vector< const VarDecl * > VarGrpTy
std::optional< StringRef > getExprText(const Expr *E, const SourceManager &SM, const LangOptions &LangOpts)
std::optional< std::string > getPointeeTypeText(const DeclaratorDecl *VD, const SourceManager &SM, const LangOptions &LangOpts, std::optional< Qualifiers > *QualifiersToAppend)
std::optional< StringRef > getRangeText(SourceRange SR, const SourceManager &SM, const LangOptions &LangOpts)
std::optional< StringRef > getVarDeclIdentifierText(const DeclaratorDecl *VD, const SourceManager &SM, const LangOptions &LangOpts)
const FunctionProtoType * T
std::optional< SourceLocation > getPastLoc(const NodeTy *Node, const SourceManager &SM, const LangOptions &LangOpts)
std::set< const Expr * > findUnsafePointers(const FunctionDecl *FD)
static bool hasUnsafePrintfStringArg(const CallExpr &Node, ASTContext &Ctx, MatchResult &Result, llvm::StringRef Tag)
static bool hasUnsafeFormatOrSArg(const CallExpr *Call, const Expr *&UnsafeArg, const unsigned FmtArgIdx, ASTContext &Ctx, bool isKprintf=false)
static bool isPredefinedUnsafeLibcFunc(const FunctionDecl &Node)
static bool hasUnsafeSnprintfBuffer(const CallExpr &Node, ASTContext &Ctx)
static bool isUnsafeVaListPrintfFunc(const FunctionDecl &Node)
static bool isNullTermPointer(const Expr *Ptr)
static bool isUnsafeSprintfFunc(const FunctionDecl &Node)
static bool isNormalPrintfFunc(const FunctionDecl &Node)
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.
StringRef matchLibcName(StringRef Name)
StringRef matchName(StringRef FunName, bool isBuiltin)
StringRef matchLibcNameOrBuiltinChk(StringRef Name)