|
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"
|
@@ -812,6 +815,59 @@ class PtrToPtrAssignmentGadget : public FixableGadget {
|
812 | 815 | }
|
813 | 816 | };
|
814 | 817 |
|
| 818 | +/// An assignment expression of the form: |
| 819 | +/// \code |
| 820 | +/// ptr = array; |
| 821 | +/// \endcode |
| 822 | +/// where `p` is a pointer and `array` is a constant size array. |
| 823 | +class CArrayToPtrAssignmentGadget : public FixableGadget { |
| 824 | +private: |
| 825 | + static constexpr const char *const PointerAssignLHSTag = "ptrLHS"; |
| 826 | + static constexpr const char *const PointerAssignRHSTag = "ptrRHS"; |
| 827 | + const DeclRefExpr * PtrLHS; // the LHS pointer expression in `PA` |
| 828 | + const DeclRefExpr * PtrRHS; // the RHS pointer expression in `PA` |
| 829 | + |
| 830 | +public: |
| 831 | + CArrayToPtrAssignmentGadget(const MatchFinder::MatchResult &Result) |
| 832 | + : FixableGadget(Kind::CArrayToPtrAssignment), |
| 833 | + PtrLHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)), |
| 834 | + PtrRHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {} |
| 835 | + |
| 836 | + static bool classof(const Gadget *G) { |
| 837 | + return G->getKind() == Kind::CArrayToPtrAssignment; |
| 838 | + } |
| 839 | + |
| 840 | + static Matcher matcher() { |
| 841 | + auto PtrAssignExpr = binaryOperator(allOf(hasOperatorName("="), |
| 842 | + hasRHS(ignoringParenImpCasts(declRefExpr(hasType(hasCanonicalType(constantArrayType())), |
| 843 | + toSupportedVariable()). |
| 844 | + bind(PointerAssignRHSTag))), |
| 845 | + hasLHS(declRefExpr(hasPointerType(), |
| 846 | + toSupportedVariable()). |
| 847 | + bind(PointerAssignLHSTag)))); |
| 848 | + |
| 849 | + return stmt(isInUnspecifiedUntypedContext(PtrAssignExpr)); |
| 850 | + } |
| 851 | + |
| 852 | + virtual std::optional<FixItList> |
| 853 | + getFixits(const FixitStrategy &S) const override; |
| 854 | + |
| 855 | + virtual const Stmt *getBaseStmt() const override { |
| 856 | + // FIXME: This should be the binary operator, assuming that this method |
| 857 | + // makes sense at all on a FixableGadget. |
| 858 | + return PtrLHS; |
| 859 | + } |
| 860 | + |
| 861 | + virtual DeclUseList getClaimedVarUseSites() const override { |
| 862 | + return DeclUseList{PtrLHS, PtrRHS}; |
| 863 | + } |
| 864 | + |
| 865 | + virtual std::optional<std::pair<const VarDecl *, const VarDecl *>> |
| 866 | + getStrategyImplications() const override { |
| 867 | + return {}; |
| 868 | + } |
| 869 | +}; |
| 870 | + |
815 | 871 | /// A call of a function or method that performs unchecked buffer operations
|
816 | 872 | /// over one of its pointer parameters.
|
817 | 873 | class UnsafeBufferUsageAttrGadget : public WarningGadget {
|
@@ -1457,6 +1513,22 @@ PtrToPtrAssignmentGadget::getFixits(const FixitStrategy &S) const {
|
1457 | 1513 | /// \returns fixit that adds .data() call after \DRE.
|
1458 | 1514 | static inline std::optional<FixItList> createDataFixit(const ASTContext& Ctx, const DeclRefExpr * DRE);
|
1459 | 1515 |
|
| 1516 | +std::optional<FixItList> |
| 1517 | +CArrayToPtrAssignmentGadget::getFixits(const FixitStrategy &S) const { |
| 1518 | + const auto *LeftVD = cast<VarDecl>(PtrLHS->getDecl()); |
| 1519 | + const auto *RightVD = cast<VarDecl>(PtrRHS->getDecl()); |
| 1520 | + if (S.lookup(LeftVD) == FixitStrategy::Kind::Span) { |
| 1521 | + if (S.lookup(RightVD) == FixitStrategy::Kind::Wontfix) { |
| 1522 | + return FixItList{}; |
| 1523 | + } |
| 1524 | + } else if (S.lookup(LeftVD) == FixitStrategy::Kind::Wontfix) { |
| 1525 | + if (S.lookup(RightVD) == FixitStrategy::Kind::Array) { |
| 1526 | + return createDataFixit(RightVD->getASTContext(), PtrRHS); |
| 1527 | + } |
| 1528 | + } |
| 1529 | + return std::nullopt; |
| 1530 | +} |
| 1531 | + |
1460 | 1532 | std::optional<FixItList>
|
1461 | 1533 | PointerInitGadget::getFixits(const FixitStrategy &S) const {
|
1462 | 1534 | const auto *LeftVD = PtrInitLHS;
|
|
0 commit comments