|
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"
|
@@ -849,6 +852,59 @@ class PtrToPtrAssignmentGadget : public FixableGadget {
|
849 | 852 | }
|
850 | 853 | };
|
851 | 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(allOf(hasOperatorName("="), |
| 879 | + hasRHS(ignoringParenImpCasts(declRefExpr(hasType(hasCanonicalType(constantArrayType())), |
| 880 | + toSupportedVariable()). |
| 881 | + bind(PointerAssignRHSTag))), |
| 882 | + hasLHS(declRefExpr(hasPointerType(), |
| 883 | + 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 | + |
852 | 908 | /// A call of a function or method that performs unchecked buffer operations
|
853 | 909 | /// over one of its pointer parameters.
|
854 | 910 | class UnsafeBufferUsageAttrGadget : public WarningGadget {
|
@@ -1494,6 +1550,22 @@ PtrToPtrAssignmentGadget::getFixits(const FixitStrategy &S) const {
|
1494 | 1550 | /// \returns fixit that adds .data() call after \DRE.
|
1495 | 1551 | static inline std::optional<FixItList> createDataFixit(const ASTContext& Ctx, const DeclRefExpr * DRE);
|
1496 | 1552 |
|
| 1553 | +std::optional<FixItList> |
| 1554 | +CArrayToPtrAssignmentGadget::getFixits(const FixitStrategy &S) const { |
| 1555 | + const auto *LeftVD = cast<VarDecl>(PtrLHS->getDecl()); |
| 1556 | + const auto *RightVD = cast<VarDecl>(PtrRHS->getDecl()); |
| 1557 | + if (S.lookup(LeftVD) == FixitStrategy::Kind::Span) { |
| 1558 | + if (S.lookup(RightVD) == FixitStrategy::Kind::Wontfix) { |
| 1559 | + return FixItList{}; |
| 1560 | + } |
| 1561 | + } else if (S.lookup(LeftVD) == FixitStrategy::Kind::Wontfix) { |
| 1562 | + if (S.lookup(RightVD) == FixitStrategy::Kind::Array) { |
| 1563 | + return createDataFixit(RightVD->getASTContext(), PtrRHS); |
| 1564 | + } |
| 1565 | + } |
| 1566 | + return std::nullopt; |
| 1567 | +} |
| 1568 | + |
1497 | 1569 | std::optional<FixItList>
|
1498 | 1570 | PointerInitGadget::getFixits(const FixitStrategy &S) const {
|
1499 | 1571 | const auto *LeftVD = PtrInitLHS;
|
|
0 commit comments