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"
@@ -760,21 +763,22 @@ class PointerInitGadget : public FixableGadget {
760
763
// / \code
761
764
// / p = q;
762
765
// / \endcode
763
- class PointerAssignmentGadget : public FixableGadget {
766
+ // / where both `p` and `q` are pointers.
767
+ class PtrToPtrAssignmentGadget : public FixableGadget {
764
768
private:
765
769
static constexpr const char *const PointerAssignLHSTag = " ptrLHS" ;
766
770
static constexpr const char *const PointerAssignRHSTag = " ptrRHS" ;
767
771
const DeclRefExpr *PtrLHS; // the LHS pointer expression in `PA`
768
772
const DeclRefExpr *PtrRHS; // the RHS pointer expression in `PA`
769
773
770
774
public:
771
- PointerAssignmentGadget (const MatchFinder::MatchResult &Result)
772
- : FixableGadget(Kind::PointerAssignment ),
775
+ PtrToPtrAssignmentGadget (const MatchFinder::MatchResult &Result)
776
+ : FixableGadget(Kind::PtrToPtrAssignment ),
773
777
PtrLHS (Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
774
778
PtrRHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
775
779
776
780
static bool classof (const Gadget *G) {
777
- return G->getKind () == Kind::PointerAssignment ;
781
+ return G->getKind () == Kind::PtrToPtrAssignment ;
778
782
}
779
783
780
784
static Matcher matcher () {
@@ -809,6 +813,60 @@ class PointerAssignmentGadget : public FixableGadget {
809
813
}
810
814
};
811
815
816
+ // / An assignment expression of the form:
817
+ // / \code
818
+ // / ptr = array;
819
+ // / \endcode
820
+ // / where `p` is a pointer and `array` is a constant size array.
821
+ class CArrayToPtrAssignmentGadget : public FixableGadget {
822
+ private:
823
+ static constexpr const char *const PointerAssignLHSTag = " ptrLHS" ;
824
+ static constexpr const char *const PointerAssignRHSTag = " ptrRHS" ;
825
+ const DeclRefExpr *PtrLHS; // the LHS pointer expression in `PA`
826
+ const DeclRefExpr *PtrRHS; // the RHS pointer expression in `PA`
827
+
828
+ public:
829
+ CArrayToPtrAssignmentGadget (const MatchFinder::MatchResult &Result)
830
+ : FixableGadget(Kind::CArrayToPtrAssignment),
831
+ PtrLHS (Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
832
+ PtrRHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
833
+
834
+ static bool classof (const Gadget *G) {
835
+ return G->getKind () == Kind::CArrayToPtrAssignment;
836
+ }
837
+
838
+ static Matcher matcher () {
839
+ auto PtrAssignExpr = binaryOperator (
840
+ allOf (hasOperatorName (" =" ),
841
+ hasRHS (ignoringParenImpCasts (
842
+ declRefExpr (hasType (hasCanonicalType (constantArrayType ())),
843
+ toSupportedVariable ())
844
+ .bind (PointerAssignRHSTag))),
845
+ hasLHS (declRefExpr (hasPointerType (), toSupportedVariable ())
846
+ .bind (PointerAssignLHSTag))));
847
+
848
+ return stmt (isInUnspecifiedUntypedContext (PtrAssignExpr));
849
+ }
850
+
851
+ virtual std::optional<FixItList>
852
+ getFixits (const FixitStrategy &S) const override ;
853
+
854
+ virtual const Stmt *getBaseStmt () const override {
855
+ // FIXME: This should be the binary operator, assuming that this method
856
+ // makes sense at all on a FixableGadget.
857
+ return PtrLHS;
858
+ }
859
+
860
+ virtual DeclUseList getClaimedVarUseSites () const override {
861
+ return DeclUseList{PtrLHS, PtrRHS};
862
+ }
863
+
864
+ virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
865
+ getStrategyImplications () const override {
866
+ return {};
867
+ }
868
+ };
869
+
812
870
// / A call of a function or method that performs unchecked buffer operations
813
871
// / over one of its pointer parameters.
814
872
class UnsafeBufferUsageAttrGadget : public WarningGadget {
@@ -1428,7 +1486,7 @@ bool clang::internal::anyConflict(const SmallVectorImpl<FixItHint> &FixIts,
1428
1486
}
1429
1487
1430
1488
std::optional<FixItList>
1431
- PointerAssignmentGadget ::getFixits (const FixitStrategy &S) const {
1489
+ PtrToPtrAssignmentGadget ::getFixits (const FixitStrategy &S) const {
1432
1490
const auto *LeftVD = cast<VarDecl>(PtrLHS->getDecl ());
1433
1491
const auto *RightVD = cast<VarDecl>(PtrRHS->getDecl ());
1434
1492
switch (S.lookup (LeftVD)) {
@@ -1447,6 +1505,42 @@ PointerAssignmentGadget::getFixits(const FixitStrategy &S) const {
1447
1505
return std::nullopt;
1448
1506
}
1449
1507
1508
+ // / \returns fixit that adds .data() call after \DRE.
1509
+ static inline std::optional<FixItList> createDataFixit (const ASTContext &Ctx,
1510
+ const DeclRefExpr *DRE);
1511
+
1512
+ std::optional<FixItList>
1513
+ CArrayToPtrAssignmentGadget::getFixits (const FixitStrategy &S) const {
1514
+ const auto *LeftVD = cast<VarDecl>(PtrLHS->getDecl ());
1515
+ const auto *RightVD = cast<VarDecl>(PtrRHS->getDecl ());
1516
+ // TLDR: Implementing fixits for non-Wontfix strategy on both LHS and RHS is
1517
+ // non-trivial.
1518
+ //
1519
+ // CArrayToPtrAssignmentGadget doesn't have strategy implications because
1520
+ // constant size array propagates its bounds. Because of that LHS and RHS are
1521
+ // addressed by two different fixits.
1522
+ //
1523
+ // At the same time FixitStrategy S doesn't reflect what group a fixit belongs
1524
+ // to and can't be generally relied on in multi-variable Fixables!
1525
+ //
1526
+ // E. g. If an instance of this gadget is fixing variable on LHS then the
1527
+ // variable on RHS is fixed by a different fixit and its strategy for LHS
1528
+ // fixit is as if Wontfix.
1529
+ //
1530
+ // The only exception is Wontfix strategy for a given variable as that is
1531
+ // valid for any fixit produced for the given input source code.
1532
+ if (S.lookup (LeftVD) == FixitStrategy::Kind::Span) {
1533
+ if (S.lookup (RightVD) == FixitStrategy::Kind::Wontfix) {
1534
+ return FixItList{};
1535
+ }
1536
+ } else if (S.lookup (LeftVD) == FixitStrategy::Kind::Wontfix) {
1537
+ if (S.lookup (RightVD) == FixitStrategy::Kind::Array) {
1538
+ return createDataFixit (RightVD->getASTContext (), PtrRHS);
1539
+ }
1540
+ }
1541
+ return std::nullopt;
1542
+ }
1543
+
1450
1544
std::optional<FixItList>
1451
1545
PointerInitGadget::getFixits (const FixitStrategy &S) const {
1452
1546
const auto *LeftVD = PtrInitLHS;
@@ -1864,6 +1958,19 @@ PointerDereferenceGadget::getFixits(const FixitStrategy &S) const {
1864
1958
return std::nullopt;
1865
1959
}
1866
1960
1961
+ static inline std::optional<FixItList> createDataFixit (const ASTContext &Ctx,
1962
+ const DeclRefExpr *DRE) {
1963
+ const SourceManager &SM = Ctx.getSourceManager ();
1964
+ // Inserts the .data() after the DRE
1965
+ std::optional<SourceLocation> EndOfOperand =
1966
+ getPastLoc (DRE, SM, Ctx.getLangOpts ());
1967
+
1968
+ if (EndOfOperand)
1969
+ return FixItList{{FixItHint::CreateInsertion (*EndOfOperand, " .data()" )}};
1970
+
1971
+ return std::nullopt;
1972
+ }
1973
+
1867
1974
// Generates fix-its replacing an expression of the form UPC(DRE) with
1868
1975
// `DRE.data()`
1869
1976
std::optional<FixItList>
@@ -1872,14 +1979,7 @@ UPCStandalonePointerGadget::getFixits(const FixitStrategy &S) const {
1872
1979
switch (S.lookup (VD)) {
1873
1980
case FixitStrategy::Kind::Array:
1874
1981
case FixitStrategy::Kind::Span: {
1875
- ASTContext &Ctx = VD->getASTContext ();
1876
- SourceManager &SM = Ctx.getSourceManager ();
1877
- // Inserts the .data() after the DRE
1878
- std::optional<SourceLocation> EndOfOperand =
1879
- getPastLoc (Node, SM, Ctx.getLangOpts ());
1880
-
1881
- if (EndOfOperand)
1882
- return FixItList{{FixItHint::CreateInsertion (*EndOfOperand, " .data()" )}};
1982
+ return createDataFixit (VD->getASTContext (), Node);
1883
1983
// FIXME: Points inside a macro expansion.
1884
1984
break ;
1885
1985
}
0 commit comments