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"
@@ -799,21 +802,22 @@ class PointerInitGadget : public FixableGadget {
799
802
// / \code
800
803
// / p = q;
801
804
// / \endcode
802
- class PointerAssignmentGadget : public FixableGadget {
805
+ // / where both `p` and `q` are pointers.
806
+ class PtrToPtrAssignmentGadget : public FixableGadget {
803
807
private:
804
808
static constexpr const char *const PointerAssignLHSTag = " ptrLHS" ;
805
809
static constexpr const char *const PointerAssignRHSTag = " ptrRHS" ;
806
810
const DeclRefExpr * PtrLHS; // the LHS pointer expression in `PA`
807
811
const DeclRefExpr * PtrRHS; // the RHS pointer expression in `PA`
808
812
809
813
public:
810
- PointerAssignmentGadget (const MatchFinder::MatchResult &Result)
811
- : FixableGadget(Kind::PointerAssignment ),
812
- PtrLHS (Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
813
- PtrRHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
814
+ PtrToPtrAssignmentGadget (const MatchFinder::MatchResult &Result)
815
+ : FixableGadget(Kind::PtrToPtrAssignment ),
816
+ PtrLHS (Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
817
+ PtrRHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
814
818
815
819
static bool classof (const Gadget *G) {
816
- return G->getKind () == Kind::PointerAssignment ;
820
+ return G->getKind () == Kind::PtrToPtrAssignment ;
817
821
}
818
822
819
823
static Matcher matcher () {
@@ -848,6 +852,60 @@ class PointerAssignmentGadget : public FixableGadget {
848
852
}
849
853
};
850
854
855
+ // / An assignment expression of the form:
856
+ // / \code
857
+ // / ptr = array;
858
+ // / \endcode
859
+ // / where `p` is a pointer and `array` is a constant size array.
860
+ class CArrayToPtrAssignmentGadget : public FixableGadget {
861
+ private:
862
+ static constexpr const char *const PointerAssignLHSTag = " ptrLHS" ;
863
+ static constexpr const char *const PointerAssignRHSTag = " ptrRHS" ;
864
+ const DeclRefExpr *PtrLHS; // the LHS pointer expression in `PA`
865
+ const DeclRefExpr *PtrRHS; // the RHS pointer expression in `PA`
866
+
867
+ public:
868
+ CArrayToPtrAssignmentGadget (const MatchFinder::MatchResult &Result)
869
+ : FixableGadget(Kind::CArrayToPtrAssignment),
870
+ PtrLHS (Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
871
+ PtrRHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
872
+
873
+ static bool classof (const Gadget *G) {
874
+ return G->getKind () == Kind::CArrayToPtrAssignment;
875
+ }
876
+
877
+ static Matcher matcher () {
878
+ auto PtrAssignExpr = binaryOperator (
879
+ allOf (hasOperatorName (" =" ),
880
+ hasRHS (ignoringParenImpCasts (
881
+ declRefExpr (hasType (hasCanonicalType (constantArrayType ())),
882
+ toSupportedVariable ())
883
+ .bind (PointerAssignRHSTag))),
884
+ hasLHS (declRefExpr (hasPointerType (), toSupportedVariable ())
885
+ .bind (PointerAssignLHSTag))));
886
+
887
+ return stmt (isInUnspecifiedUntypedContext (PtrAssignExpr));
888
+ }
889
+
890
+ virtual std::optional<FixItList>
891
+ getFixits (const FixitStrategy &S) const override ;
892
+
893
+ virtual const Stmt *getBaseStmt () const override {
894
+ // FIXME: This should be the binary operator, assuming that this method
895
+ // makes sense at all on a FixableGadget.
896
+ return PtrLHS;
897
+ }
898
+
899
+ virtual DeclUseList getClaimedVarUseSites () const override {
900
+ return DeclUseList{PtrLHS, PtrRHS};
901
+ }
902
+
903
+ virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
904
+ getStrategyImplications () const override {
905
+ return {};
906
+ }
907
+ };
908
+
851
909
// / A call of a function or method that performs unchecked buffer operations
852
910
// / over one of its pointer parameters.
853
911
class UnsafeBufferUsageAttrGadget : public WarningGadget {
@@ -1471,7 +1529,7 @@ bool clang::internal::anyConflict(const SmallVectorImpl<FixItHint> &FixIts,
1471
1529
}
1472
1530
1473
1531
std::optional<FixItList>
1474
- PointerAssignmentGadget ::getFixits (const FixitStrategy &S) const {
1532
+ PtrToPtrAssignmentGadget ::getFixits (const FixitStrategy &S) const {
1475
1533
const auto *LeftVD = cast<VarDecl>(PtrLHS->getDecl ());
1476
1534
const auto *RightVD = cast<VarDecl>(PtrRHS->getDecl ());
1477
1535
switch (S.lookup (LeftVD)) {
@@ -1490,6 +1548,42 @@ PointerAssignmentGadget::getFixits(const FixitStrategy &S) const {
1490
1548
return std::nullopt;
1491
1549
}
1492
1550
1551
+ // / \returns fixit that adds .data() call after \DRE.
1552
+ static inline std::optional<FixItList> createDataFixit (const ASTContext &Ctx,
1553
+ const DeclRefExpr *DRE);
1554
+
1555
+ std::optional<FixItList>
1556
+ CArrayToPtrAssignmentGadget::getFixits (const FixitStrategy &S) const {
1557
+ const auto *LeftVD = cast<VarDecl>(PtrLHS->getDecl ());
1558
+ const auto *RightVD = cast<VarDecl>(PtrRHS->getDecl ());
1559
+ // TLDR: Implementing fixits for non-Wontfix strategy on both LHS and RHS is
1560
+ // non-trivial.
1561
+ //
1562
+ // CArrayToPtrAssignmentGadget doesn't have strategy implications because
1563
+ // constant size array propagates its bounds. Because of that LHS and RHS are
1564
+ // addressed by two different fixits.
1565
+ //
1566
+ // At the same time FixitStrategy S doesn't reflect what group a fixit belongs
1567
+ // to and can't be generally relied on in multi-variable Fixables!
1568
+ //
1569
+ // E. g. If an instance of this gadget is fixing variable on LHS then the
1570
+ // variable on RHS is fixed by a different fixit and its strategy for LHS
1571
+ // fixit is as if Wontfix.
1572
+ //
1573
+ // The only exception is Wontfix strategy for a given variable as that is
1574
+ // valid for any fixit produced for the given input source code.
1575
+ if (S.lookup (LeftVD) == FixitStrategy::Kind::Span) {
1576
+ if (S.lookup (RightVD) == FixitStrategy::Kind::Wontfix) {
1577
+ return FixItList{};
1578
+ }
1579
+ } else if (S.lookup (LeftVD) == FixitStrategy::Kind::Wontfix) {
1580
+ if (S.lookup (RightVD) == FixitStrategy::Kind::Array) {
1581
+ return createDataFixit (RightVD->getASTContext (), PtrRHS);
1582
+ }
1583
+ }
1584
+ return std::nullopt;
1585
+ }
1586
+
1493
1587
std::optional<FixItList>
1494
1588
PointerInitGadget::getFixits (const FixitStrategy &S) const {
1495
1589
const auto *LeftVD = PtrInitLHS;
@@ -1907,6 +2001,19 @@ PointerDereferenceGadget::getFixits(const FixitStrategy &S) const {
1907
2001
return std::nullopt;
1908
2002
}
1909
2003
2004
+ static inline std::optional<FixItList> createDataFixit (const ASTContext &Ctx,
2005
+ const DeclRefExpr *DRE) {
2006
+ const SourceManager &SM = Ctx.getSourceManager ();
2007
+ // Inserts the .data() after the DRE
2008
+ std::optional<SourceLocation> EndOfOperand =
2009
+ getPastLoc (DRE, SM, Ctx.getLangOpts ());
2010
+
2011
+ if (EndOfOperand)
2012
+ return FixItList{{FixItHint::CreateInsertion (*EndOfOperand, " .data()" )}};
2013
+
2014
+ return std::nullopt;
2015
+ }
2016
+
1910
2017
// Generates fix-its replacing an expression of the form UPC(DRE) with
1911
2018
// `DRE.data()`
1912
2019
std::optional<FixItList>
@@ -1915,14 +2022,7 @@ UPCStandalonePointerGadget::getFixits(const FixitStrategy &S) const {
1915
2022
switch (S.lookup (VD)) {
1916
2023
case FixitStrategy::Kind::Array:
1917
2024
case FixitStrategy::Kind::Span: {
1918
- ASTContext &Ctx = VD->getASTContext ();
1919
- SourceManager &SM = Ctx.getSourceManager ();
1920
- // Inserts the .data() after the DRE
1921
- std::optional<SourceLocation> EndOfOperand =
1922
- getPastLoc (Node, SM, Ctx.getLangOpts ());
1923
-
1924
- if (EndOfOperand)
1925
- return FixItList{{FixItHint::CreateInsertion (*EndOfOperand, " .data()" )}};
2025
+ return createDataFixit (VD->getASTContext (), Node);
1926
2026
// FIXME: Points inside a macro expansion.
1927
2027
break ;
1928
2028
}
0 commit comments