diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index aa8fe907b1671..1d273e77ef0b5 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -469,6 +469,20 @@ class TransferVisitor : public ConstStmtVisitor { Env.setValue(Loc, Env.create(*ThisPointeeLoc)); } + void VisitCXXNewExpr(const CXXNewExpr *S) { + auto &Loc = Env.createStorageLocation(*S); + Env.setStorageLocation(*S, Loc); + if (Value *Val = Env.createValue(S->getType())) + Env.setValue(Loc, *Val); + } + + void VisitCXXDeleteExpr(const CXXDeleteExpr *S) { + // Empty method. + // We consciously don't do anything on deletes. Diagnosing double deletes + // (for example) should be done by a specific analysis, not by the + // framework. + } + void VisitReturnStmt(const ReturnStmt *S) { if (!Env.getAnalysisOptions().ContextSensitiveOpts) return; diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 1bb772a93bda6..8f02161834dc8 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -5170,4 +5170,66 @@ TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) { }); } +TEST(TransferTest, NewExpressions) { + std::string Code = R"( + void target() { + int *p = new int(42); + // [[after_new]] + } + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + const Environment &Env = + getEnvironmentAtAnnotation(Results, "after_new"); + + auto &P = getValueForDecl(ASTCtx, Env, "p"); + + EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull()); + }); +} + +TEST(TransferTest, NewExpressions_Structs) { + std::string Code = R"( + struct Inner { + int InnerField; + }; + + struct Outer { + Inner OuterField; + }; + + void target() { + Outer *p = new Outer; + // Access the fields to make sure the analysis actually generates children + // for them in the `AggregateStorageLoc` and `StructValue`. + p->OuterField.InnerField; + // [[after_new]] + } + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + const Environment &Env = + getEnvironmentAtAnnotation(Results, "after_new"); + + const ValueDecl *OuterField = findValueDecl(ASTCtx, "OuterField"); + const ValueDecl *InnerField = findValueDecl(ASTCtx, "InnerField"); + + auto &P = getValueForDecl(ASTCtx, Env, "p"); + + auto &OuterLoc = cast(P.getPointeeLoc()); + auto &OuterFieldLoc = + cast(OuterLoc.getChild(*OuterField)); + auto &InnerFieldLoc = OuterFieldLoc.getChild(*InnerField); + + // Values for the struct and all fields exist after the new. + EXPECT_THAT(Env.getValue(OuterLoc), NotNull()); + EXPECT_THAT(Env.getValue(OuterFieldLoc), NotNull()); + EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull()); + }); +} + } // namespace