@@ -492,7 +492,9 @@ class Gadget {
492492#endif
493493
494494 virtual bool isWarningGadget () const = 0;
495- virtual const Stmt *getBaseStmt () const = 0;
495+ // TODO remove this method from WarningGadget interface. It's only used for
496+ // debug prints in FixableGadget.
497+ virtual SourceLocation getSourceLoc () const = 0;
496498
497499 // / Returns the list of pointer-type variables on which this gadget performs
498500 // / its operation. Typically, there's only one variable. This isn't a list
@@ -513,6 +515,10 @@ class WarningGadget : public Gadget {
513515
514516 static bool classof (const Gadget *G) { return G->isWarningGadget (); }
515517 bool isWarningGadget () const final { return true ; }
518+
519+ virtual void handleUnsafeOperation (UnsafeBufferUsageHandler &Handler,
520+ bool IsRelatedToDecl,
521+ ASTContext &Ctx) const = 0;
516522};
517523
518524// / Fixable gadgets correspond to code patterns that aren't always unsafe but
@@ -572,7 +578,12 @@ class IncrementGadget : public WarningGadget {
572578 .bind (OpTag));
573579 }
574580
575- const UnaryOperator *getBaseStmt () const override { return Op; }
581+ void handleUnsafeOperation (UnsafeBufferUsageHandler &Handler,
582+ bool IsRelatedToDecl,
583+ ASTContext &Ctx) const override {
584+ Handler.handleUnsafeOperation (Op, IsRelatedToDecl, Ctx);
585+ }
586+ SourceLocation getSourceLoc () const override { return Op->getBeginLoc (); }
576587
577588 DeclUseList getClaimedVarUseSites () const override {
578589 SmallVector<const DeclRefExpr *, 2 > Uses;
@@ -607,7 +618,12 @@ class DecrementGadget : public WarningGadget {
607618 .bind (OpTag));
608619 }
609620
610- const UnaryOperator *getBaseStmt () const override { return Op; }
621+ void handleUnsafeOperation (UnsafeBufferUsageHandler &Handler,
622+ bool IsRelatedToDecl,
623+ ASTContext &Ctx) const override {
624+ Handler.handleUnsafeOperation (Op, IsRelatedToDecl, Ctx);
625+ }
626+ SourceLocation getSourceLoc () const override { return Op->getBeginLoc (); }
611627
612628 DeclUseList getClaimedVarUseSites () const override {
613629 if (const auto *DRE =
@@ -648,7 +664,12 @@ class ArraySubscriptGadget : public WarningGadget {
648664 // clang-format on
649665 }
650666
651- const ArraySubscriptExpr *getBaseStmt () const override { return ASE; }
667+ void handleUnsafeOperation (UnsafeBufferUsageHandler &Handler,
668+ bool IsRelatedToDecl,
669+ ASTContext &Ctx) const override {
670+ Handler.handleUnsafeOperation (ASE, IsRelatedToDecl, Ctx);
671+ }
672+ SourceLocation getSourceLoc () const override { return ASE->getBeginLoc (); }
652673
653674 DeclUseList getClaimedVarUseSites () const override {
654675 if (const auto *DRE =
@@ -696,7 +717,12 @@ class PointerArithmeticGadget : public WarningGadget {
696717 .bind (PointerArithmeticTag));
697718 }
698719
699- const Stmt *getBaseStmt () const override { return PA; }
720+ void handleUnsafeOperation (UnsafeBufferUsageHandler &Handler,
721+ bool IsRelatedToDecl,
722+ ASTContext &Ctx) const override {
723+ Handler.handleUnsafeOperation (PA, IsRelatedToDecl, Ctx);
724+ }
725+ SourceLocation getSourceLoc () const override { return PA->getBeginLoc (); }
700726
701727 DeclUseList getClaimedVarUseSites () const override {
702728 if (const auto *DRE = dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts ())) {
@@ -734,7 +760,12 @@ class SpanTwoParamConstructorGadget : public WarningGadget {
734760 .bind (SpanTwoParamConstructorTag));
735761 }
736762
737- const Stmt *getBaseStmt () const override { return Ctor; }
763+ void handleUnsafeOperation (UnsafeBufferUsageHandler &Handler,
764+ bool IsRelatedToDecl,
765+ ASTContext &Ctx) const override {
766+ Handler.handleUnsafeOperationInContainer (Ctor, IsRelatedToDecl, Ctx);
767+ }
768+ SourceLocation getSourceLoc () const override { return Ctor->getBeginLoc (); }
738769
739770 DeclUseList getClaimedVarUseSites () const override {
740771 // If the constructor call is of the form `std::span{var, n}`, `var` is
@@ -780,11 +811,8 @@ class PointerInitGadget : public FixableGadget {
780811
781812 virtual std::optional<FixItList>
782813 getFixits (const FixitStrategy &S) const override ;
783-
784- virtual const Stmt *getBaseStmt () const override {
785- // FIXME: This needs to be the entire DeclStmt, assuming that this method
786- // makes sense at all on a FixableGadget.
787- return PtrInitRHS;
814+ SourceLocation getSourceLoc () const override {
815+ return PtrInitRHS->getBeginLoc ();
788816 }
789817
790818 virtual DeclUseList getClaimedVarUseSites () const override {
@@ -833,12 +861,7 @@ class PtrToPtrAssignmentGadget : public FixableGadget {
833861
834862 virtual std::optional<FixItList>
835863 getFixits (const FixitStrategy &S) const override ;
836-
837- virtual const Stmt *getBaseStmt () const override {
838- // FIXME: This should be the binary operator, assuming that this method
839- // makes sense at all on a FixableGadget.
840- return PtrLHS;
841- }
864+ SourceLocation getSourceLoc () const override { return PtrLHS->getBeginLoc (); }
842865
843866 virtual DeclUseList getClaimedVarUseSites () const override {
844867 return DeclUseList{PtrLHS, PtrRHS};
@@ -888,12 +911,7 @@ class CArrayToPtrAssignmentGadget : public FixableGadget {
888911
889912 virtual std::optional<FixItList>
890913 getFixits (const FixitStrategy &S) const override ;
891-
892- virtual const Stmt *getBaseStmt () const override {
893- // FIXME: This should be the binary operator, assuming that this method
894- // makes sense at all on a FixableGadget.
895- return PtrLHS;
896- }
914+ SourceLocation getSourceLoc () const override { return PtrLHS->getBeginLoc (); }
897915
898916 virtual DeclUseList getClaimedVarUseSites () const override {
899917 return DeclUseList{PtrLHS, PtrRHS};
@@ -921,10 +939,53 @@ class UnsafeBufferUsageAttrGadget : public WarningGadget {
921939 }
922940
923941 static Matcher matcher () {
924- return stmt (callExpr (callee (functionDecl (hasAttr (attr::UnsafeBufferUsage))))
925- .bind (OpTag));
942+ auto HasUnsafeFnDecl =
943+ callee (functionDecl (hasAttr (attr::UnsafeBufferUsage)));
944+ return stmt (callExpr (HasUnsafeFnDecl).bind (OpTag));
945+ }
946+
947+ void handleUnsafeOperation (UnsafeBufferUsageHandler &Handler,
948+ bool IsRelatedToDecl,
949+ ASTContext &Ctx) const override {
950+ Handler.handleUnsafeOperation (Op, IsRelatedToDecl, Ctx);
926951 }
927- const Stmt *getBaseStmt () const override { return Op; }
952+ SourceLocation getSourceLoc () const override { return Op->getBeginLoc (); }
953+
954+ DeclUseList getClaimedVarUseSites () const override { return {}; }
955+ };
956+
957+ // / A call of a constructor that performs unchecked buffer operations
958+ // / over one of its pointer parameters, or constructs a class object that will
959+ // / perform buffer operations that depend on the correctness of the parameters.
960+ class UnsafeBufferUsageCtorAttrGadget : public WarningGadget {
961+ constexpr static const char *const OpTag = " cxx_construct_expr" ;
962+ const CXXConstructExpr *Op;
963+
964+ public:
965+ UnsafeBufferUsageCtorAttrGadget (const MatchFinder::MatchResult &Result)
966+ : WarningGadget(Kind::UnsafeBufferUsageCtorAttr),
967+ Op (Result.Nodes.getNodeAs<CXXConstructExpr>(OpTag)) {}
968+
969+ static bool classof (const Gadget *G) {
970+ return G->getKind () == Kind::UnsafeBufferUsageCtorAttr;
971+ }
972+
973+ static Matcher matcher () {
974+ auto HasUnsafeCtorDecl =
975+ hasDeclaration (cxxConstructorDecl (hasAttr (attr::UnsafeBufferUsage)));
976+ // std::span(ptr, size) ctor is handled by SpanTwoParamConstructorGadget.
977+ auto HasTwoParamSpanCtorDecl = SpanTwoParamConstructorGadget::matcher ();
978+ return stmt (
979+ cxxConstructExpr (HasUnsafeCtorDecl, unless (HasTwoParamSpanCtorDecl))
980+ .bind (OpTag));
981+ }
982+
983+ void handleUnsafeOperation (UnsafeBufferUsageHandler &Handler,
984+ bool IsRelatedToDecl,
985+ ASTContext &Ctx) const override {
986+ Handler.handleUnsafeOperation (Op, IsRelatedToDecl, Ctx);
987+ }
988+ SourceLocation getSourceLoc () const override { return Op->getBeginLoc (); }
928989
929990 DeclUseList getClaimedVarUseSites () const override { return {}; }
930991};
@@ -953,7 +1014,13 @@ class DataInvocationGadget : public WarningGadget {
9531014 explicitCastExpr (anyOf (has (callExpr), has (parenExpr (has (callExpr)))))
9541015 .bind (OpTag));
9551016 }
956- const Stmt *getBaseStmt () const override { return Op; }
1017+
1018+ void handleUnsafeOperation (UnsafeBufferUsageHandler &Handler,
1019+ bool IsRelatedToDecl,
1020+ ASTContext &Ctx) const override {
1021+ Handler.handleUnsafeOperation (Op, IsRelatedToDecl, Ctx);
1022+ }
1023+ SourceLocation getSourceLoc () const override { return Op->getBeginLoc (); }
9571024
9581025 DeclUseList getClaimedVarUseSites () const override { return {}; }
9591026};
@@ -990,8 +1057,7 @@ class ULCArraySubscriptGadget : public FixableGadget {
9901057
9911058 virtual std::optional<FixItList>
9921059 getFixits (const FixitStrategy &S) const override ;
993-
994- virtual const Stmt *getBaseStmt () const override { return Node; }
1060+ SourceLocation getSourceLoc () const override { return Node->getBeginLoc (); }
9951061
9961062 virtual DeclUseList getClaimedVarUseSites () const override {
9971063 if (const auto *DRE =
@@ -1031,8 +1097,7 @@ class UPCStandalonePointerGadget : public FixableGadget {
10311097
10321098 virtual std::optional<FixItList>
10331099 getFixits (const FixitStrategy &S) const override ;
1034-
1035- virtual const Stmt *getBaseStmt () const override { return Node; }
1100+ SourceLocation getSourceLoc () const override { return Node->getBeginLoc (); }
10361101
10371102 virtual DeclUseList getClaimedVarUseSites () const override { return {Node}; }
10381103};
@@ -1070,10 +1135,9 @@ class PointerDereferenceGadget : public FixableGadget {
10701135 return {BaseDeclRefExpr};
10711136 }
10721137
1073- virtual const Stmt *getBaseStmt () const final { return Op; }
1074-
10751138 virtual std::optional<FixItList>
10761139 getFixits (const FixitStrategy &S) const override ;
1140+ SourceLocation getSourceLoc () const override { return Op->getBeginLoc (); }
10771141};
10781142
10791143// Represents expressions of the form `&DRE[any]` in the Unspecified Pointer
@@ -1108,8 +1172,7 @@ class UPCAddressofArraySubscriptGadget : public FixableGadget {
11081172
11091173 virtual std::optional<FixItList>
11101174 getFixits (const FixitStrategy &) const override ;
1111-
1112- virtual const Stmt *getBaseStmt () const override { return Node; }
1175+ SourceLocation getSourceLoc () const override { return Node->getBeginLoc (); }
11131176
11141177 virtual DeclUseList getClaimedVarUseSites () const override {
11151178 const auto *ArraySubst = cast<ArraySubscriptExpr>(Node->getSubExpr ());
@@ -1218,8 +1281,7 @@ class UPCPreIncrementGadget : public FixableGadget {
12181281
12191282 virtual std::optional<FixItList>
12201283 getFixits (const FixitStrategy &S) const override ;
1221-
1222- virtual const Stmt *getBaseStmt () const override { return Node; }
1284+ SourceLocation getSourceLoc () const override { return Node->getBeginLoc (); }
12231285
12241286 virtual DeclUseList getClaimedVarUseSites () const override {
12251287 return {dyn_cast<DeclRefExpr>(Node->getSubExpr ())};
@@ -1264,8 +1326,7 @@ class UUCAddAssignGadget : public FixableGadget {
12641326
12651327 virtual std::optional<FixItList>
12661328 getFixits (const FixitStrategy &S) const override ;
1267-
1268- virtual const Stmt *getBaseStmt () const override { return Node; }
1329+ SourceLocation getSourceLoc () const override { return Node->getBeginLoc (); }
12691330
12701331 virtual DeclUseList getClaimedVarUseSites () const override {
12711332 return {dyn_cast<DeclRefExpr>(Node->getLHS ())};
@@ -1315,9 +1376,9 @@ class DerefSimplePtrArithFixableGadget : public FixableGadget {
13151376
13161377 virtual std::optional<FixItList>
13171378 getFixits (const FixitStrategy &s) const final ;
1318-
1319- // TODO remove this method from FixableGadget interface
1320- virtual const Stmt * getBaseStmt () const final { return nullptr ; }
1379+ SourceLocation getSourceLoc () const override {
1380+ return DerefOp-> getBeginLoc ();
1381+ }
13211382
13221383 virtual DeclUseList getClaimedVarUseSites () const final {
13231384 return {BaseDeclRefExpr};
@@ -2070,7 +2131,7 @@ UUCAddAssignGadget::getFixits(const FixitStrategy &S) const {
20702131 if (S.lookup (VD) == FixitStrategy::Kind::Span) {
20712132 FixItList Fixes;
20722133
2073- const Stmt *AddAssignNode = getBaseStmt () ;
2134+ const Stmt *AddAssignNode = Node ;
20742135 StringRef varName = VD->getName ();
20752136 const ASTContext &Ctx = VD->getASTContext ();
20762137
@@ -2112,20 +2173,19 @@ UPCPreIncrementGadget::getFixits(const FixitStrategy &S) const {
21122173 if (S.lookup (VD) == FixitStrategy::Kind::Span) {
21132174 FixItList Fixes;
21142175 std::stringstream SS;
2115- const Stmt *PreIncNode = getBaseStmt ();
21162176 StringRef varName = VD->getName ();
21172177 const ASTContext &Ctx = VD->getASTContext ();
21182178
21192179 // To transform UPC(++p) to UPC((p = p.subspan(1)).data()):
21202180 SS << " (" << varName.data () << " = " << varName.data ()
21212181 << " .subspan(1)).data()" ;
21222182 std::optional<SourceLocation> PreIncLocation =
2123- getEndCharLoc (PreIncNode , Ctx.getSourceManager (), Ctx.getLangOpts ());
2183+ getEndCharLoc (Node , Ctx.getSourceManager (), Ctx.getLangOpts ());
21242184 if (!PreIncLocation)
21252185 return std::nullopt ;
21262186
21272187 Fixes.push_back (FixItHint::CreateReplacement (
2128- SourceRange (PreIncNode ->getBeginLoc (), *PreIncLocation), SS.str ()));
2188+ SourceRange (Node ->getBeginLoc (), *PreIncLocation), SS.str ()));
21292189 return Fixes;
21302190 }
21312191 }
@@ -2856,7 +2916,7 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const FixitStrategy &S,
28562916 }
28572917#ifndef NDEBUG
28582918 Handler.addDebugNoteForVar (
2859- VD, F->getBaseStmt ()-> getBeginLoc (),
2919+ VD, F->getSourceLoc (),
28602920 (" gadget '" + F->getDebugName () + " ' refused to produce a fix" )
28612921 .str ());
28622922#endif
@@ -3008,8 +3068,8 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
30083068 // every problematic operation and consider it done. No need to deal
30093069 // with fixable gadgets, no need to group operations by variable.
30103070 for (const auto &G : WarningGadgets) {
3011- Handler. handleUnsafeOperation ( G->getBaseStmt () , /* IsRelatedToDecl=*/ false ,
3012- D->getASTContext ());
3071+ G->handleUnsafeOperation (Handler , /* IsRelatedToDecl=*/ false ,
3072+ D->getASTContext ());
30133073 }
30143074
30153075 // This return guarantees that most of the machine doesn't run when
@@ -3251,8 +3311,8 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
32513311 Tracker, Handler, VarGrpMgr);
32523312
32533313 for (const auto &G : UnsafeOps.noVar ) {
3254- Handler. handleUnsafeOperation ( G->getBaseStmt () , /* IsRelatedToDecl=*/ false ,
3255- D->getASTContext ());
3314+ G->handleUnsafeOperation (Handler , /* IsRelatedToDecl=*/ false ,
3315+ D->getASTContext ());
32563316 }
32573317
32583318 for (const auto &[VD, WarningGadgets] : UnsafeOps.byVar ) {
@@ -3263,8 +3323,8 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
32633323 : FixItList{},
32643324 D, NaiveStrategy);
32653325 for (const auto &G : WarningGadgets) {
3266- Handler. handleUnsafeOperation ( G->getBaseStmt () , /* IsRelatedToDecl=*/ true ,
3267- D->getASTContext ());
3326+ G->handleUnsafeOperation (Handler , /* IsRelatedToDecl=*/ true ,
3327+ D->getASTContext ());
32683328 }
32693329 }
32703330}
0 commit comments