7
7
// ===----------------------------------------------------------------------===//
8
8
9
9
#include " clang/Analysis/Analyses/UnsafeBufferUsage.h"
10
+ #include " clang/AST/ASTContext.h"
10
11
#include " clang/AST/Decl.h"
11
12
#include " clang/AST/Expr.h"
12
13
#include " clang/AST/RecursiveASTVisitor.h"
14
+ #include " clang/AST/Stmt.h"
13
15
#include " clang/AST/StmtVisitor.h"
14
16
#include " clang/ASTMatchers/ASTMatchFinder.h"
17
+ #include " clang/ASTMatchers/ASTMatchers.h"
15
18
#include " clang/Basic/CharInfo.h"
16
19
#include " clang/Basic/SourceLocation.h"
17
20
#include " clang/Lex/Lexer.h"
@@ -798,21 +801,22 @@ class PointerInitGadget : public FixableGadget {
798
801
// / \code
799
802
// / p = q;
800
803
// / \endcode
801
- class PointerAssignmentGadget : public FixableGadget {
804
+ // / where both `p` and `q` are pointers.
805
+ class PtrToPtrAssignmentGadget : public FixableGadget {
802
806
private:
803
807
static constexpr const char *const PointerAssignLHSTag = " ptrLHS" ;
804
808
static constexpr const char *const PointerAssignRHSTag = " ptrRHS" ;
805
809
const DeclRefExpr *PtrLHS; // the LHS pointer expression in `PA`
806
810
const DeclRefExpr *PtrRHS; // the RHS pointer expression in `PA`
807
811
808
812
public:
809
- PointerAssignmentGadget (const MatchFinder::MatchResult &Result)
810
- : FixableGadget(Kind::PointerAssignment ),
813
+ PtrToPtrAssignmentGadget (const MatchFinder::MatchResult &Result)
814
+ : FixableGadget(Kind::PtrToPtrAssignment ),
811
815
PtrLHS (Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
812
816
PtrRHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
813
817
814
818
static bool classof (const Gadget *G) {
815
- return G->getKind () == Kind::PointerAssignment ;
819
+ return G->getKind () == Kind::PtrToPtrAssignment ;
816
820
}
817
821
818
822
static Matcher matcher () {
@@ -847,6 +851,60 @@ class PointerAssignmentGadget : public FixableGadget {
847
851
}
848
852
};
849
853
854
+ // / An assignment expression of the form:
855
+ // / \code
856
+ // / ptr = array;
857
+ // / \endcode
858
+ // / where `p` is a pointer and `array` is a constant size array.
859
+ class CArrayToPtrAssignmentGadget : public FixableGadget {
860
+ private:
861
+ static constexpr const char *const PointerAssignLHSTag = " ptrLHS" ;
862
+ static constexpr const char *const PointerAssignRHSTag = " ptrRHS" ;
863
+ const DeclRefExpr *PtrLHS; // the LHS pointer expression in `PA`
864
+ const DeclRefExpr *PtrRHS; // the RHS pointer expression in `PA`
865
+
866
+ public:
867
+ CArrayToPtrAssignmentGadget (const MatchFinder::MatchResult &Result)
868
+ : FixableGadget(Kind::CArrayToPtrAssignment),
869
+ PtrLHS (Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
870
+ PtrRHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
871
+
872
+ static bool classof (const Gadget *G) {
873
+ return G->getKind () == Kind::CArrayToPtrAssignment;
874
+ }
875
+
876
+ static Matcher matcher () {
877
+ auto PtrAssignExpr = binaryOperator (
878
+ allOf (hasOperatorName (" =" ),
879
+ hasRHS (ignoringParenImpCasts (
880
+ declRefExpr (hasType (hasCanonicalType (constantArrayType ())),
881
+ toSupportedVariable ())
882
+ .bind (PointerAssignRHSTag))),
883
+ hasLHS (declRefExpr (hasPointerType (), toSupportedVariable ())
884
+ .bind (PointerAssignLHSTag))));
885
+
886
+ return stmt (isInUnspecifiedUntypedContext (PtrAssignExpr));
887
+ }
888
+
889
+ virtual std::optional<FixItList>
890
+ 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
+ }
897
+
898
+ virtual DeclUseList getClaimedVarUseSites () const override {
899
+ return DeclUseList{PtrLHS, PtrRHS};
900
+ }
901
+
902
+ virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
903
+ getStrategyImplications () const override {
904
+ return {};
905
+ }
906
+ };
907
+
850
908
// / A call of a function or method that performs unchecked buffer operations
851
909
// / over one of its pointer parameters.
852
910
class UnsafeBufferUsageAttrGadget : public WarningGadget {
@@ -1466,7 +1524,7 @@ bool clang::internal::anyConflict(const SmallVectorImpl<FixItHint> &FixIts,
1466
1524
}
1467
1525
1468
1526
std::optional<FixItList>
1469
- PointerAssignmentGadget ::getFixits (const FixitStrategy &S) const {
1527
+ PtrToPtrAssignmentGadget ::getFixits (const FixitStrategy &S) const {
1470
1528
const auto *LeftVD = cast<VarDecl>(PtrLHS->getDecl ());
1471
1529
const auto *RightVD = cast<VarDecl>(PtrRHS->getDecl ());
1472
1530
switch (S.lookup (LeftVD)) {
@@ -1485,6 +1543,42 @@ PointerAssignmentGadget::getFixits(const FixitStrategy &S) const {
1485
1543
return std::nullopt;
1486
1544
}
1487
1545
1546
+ // / \returns fixit that adds .data() call after \DRE.
1547
+ static inline std::optional<FixItList> createDataFixit (const ASTContext &Ctx,
1548
+ const DeclRefExpr *DRE);
1549
+
1550
+ std::optional<FixItList>
1551
+ CArrayToPtrAssignmentGadget::getFixits (const FixitStrategy &S) const {
1552
+ const auto *LeftVD = cast<VarDecl>(PtrLHS->getDecl ());
1553
+ const auto *RightVD = cast<VarDecl>(PtrRHS->getDecl ());
1554
+ // TLDR: Implementing fixits for non-Wontfix strategy on both LHS and RHS is
1555
+ // non-trivial.
1556
+ //
1557
+ // CArrayToPtrAssignmentGadget doesn't have strategy implications because
1558
+ // constant size array propagates its bounds. Because of that LHS and RHS are
1559
+ // addressed by two different fixits.
1560
+ //
1561
+ // At the same time FixitStrategy S doesn't reflect what group a fixit belongs
1562
+ // to and can't be generally relied on in multi-variable Fixables!
1563
+ //
1564
+ // E. g. If an instance of this gadget is fixing variable on LHS then the
1565
+ // variable on RHS is fixed by a different fixit and its strategy for LHS
1566
+ // fixit is as if Wontfix.
1567
+ //
1568
+ // The only exception is Wontfix strategy for a given variable as that is
1569
+ // valid for any fixit produced for the given input source code.
1570
+ if (S.lookup (LeftVD) == FixitStrategy::Kind::Span) {
1571
+ if (S.lookup (RightVD) == FixitStrategy::Kind::Wontfix) {
1572
+ return FixItList{};
1573
+ }
1574
+ } else if (S.lookup (LeftVD) == FixitStrategy::Kind::Wontfix) {
1575
+ if (S.lookup (RightVD) == FixitStrategy::Kind::Array) {
1576
+ return createDataFixit (RightVD->getASTContext (), PtrRHS);
1577
+ }
1578
+ }
1579
+ return std::nullopt;
1580
+ }
1581
+
1488
1582
std::optional<FixItList>
1489
1583
PointerInitGadget::getFixits (const FixitStrategy &S) const {
1490
1584
const auto *LeftVD = PtrInitLHS;
@@ -1902,6 +1996,19 @@ PointerDereferenceGadget::getFixits(const FixitStrategy &S) const {
1902
1996
return std::nullopt;
1903
1997
}
1904
1998
1999
+ static inline std::optional<FixItList> createDataFixit (const ASTContext &Ctx,
2000
+ const DeclRefExpr *DRE) {
2001
+ const SourceManager &SM = Ctx.getSourceManager ();
2002
+ // Inserts the .data() after the DRE
2003
+ std::optional<SourceLocation> EndOfOperand =
2004
+ getPastLoc (DRE, SM, Ctx.getLangOpts ());
2005
+
2006
+ if (EndOfOperand)
2007
+ return FixItList{{FixItHint::CreateInsertion (*EndOfOperand, " .data()" )}};
2008
+
2009
+ return std::nullopt;
2010
+ }
2011
+
1905
2012
// Generates fix-its replacing an expression of the form UPC(DRE) with
1906
2013
// `DRE.data()`
1907
2014
std::optional<FixItList>
@@ -1910,14 +2017,7 @@ UPCStandalonePointerGadget::getFixits(const FixitStrategy &S) const {
1910
2017
switch (S.lookup (VD)) {
1911
2018
case FixitStrategy::Kind::Array:
1912
2019
case FixitStrategy::Kind::Span: {
1913
- ASTContext &Ctx = VD->getASTContext ();
1914
- SourceManager &SM = Ctx.getSourceManager ();
1915
- // Inserts the .data() after the DRE
1916
- std::optional<SourceLocation> EndOfOperand =
1917
- getPastLoc (Node, SM, Ctx.getLangOpts ());
1918
-
1919
- if (EndOfOperand)
1920
- return FixItList{{FixItHint::CreateInsertion (*EndOfOperand, " .data()" )}};
2020
+ return createDataFixit (VD->getASTContext (), Node);
1921
2021
// FIXME: Points inside a macro expansion.
1922
2022
break ;
1923
2023
}
0 commit comments