baloghadamsoftware updated this revision to Diff 265926.
baloghadamsoftware added a comment.

Merged `retrieveFromConstructionContext()` to `handleConstructionContext()`.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D80366/new/

https://reviews.llvm.org/D80366

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  clang/lib/StaticAnalyzer/Core/CallEvent.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/unittests/StaticAnalyzer/CMakeLists.txt
  clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp

Index: clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
===================================================================
--- /dev/null
+++ clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
@@ -0,0 +1,55 @@
+//===- unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp ------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
+#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ento {
+namespace {
+
+class TestReturnValueUnderConstructionChecker
+  : public Checker<check::PostCall> {
+public:
+  void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
+    if (!Call.getOriginExpr())
+      return;
+
+    Optional<SVal> RetVal = Call.getReturnValueUnderConstruction(0);
+    assert(RetVal);
+    assert(RetVal->getAsRegion());
+  }
+};
+
+void addTestReturnValueUnderConstructionChecker(
+    AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) {
+  AnOpts.CheckersAndPackages =
+    {{"test.TestReturnValueUnderConstruction", true}};
+  AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
+      Registry.addChecker<TestReturnValueUnderConstructionChecker>(
+          "test.TestReturnValueUnderConstruction", "", "");
+    });
+}
+
+TEST(TestReturnValueUnderConstructionChecker,
+     ReturnValueUnderConstructionChecker) {
+  EXPECT_TRUE(runCheckerOnCode<addTestReturnValueUnderConstructionChecker>(
+                  "class C { public: C(int nn): n(nn) {} virtual ~C() {} "
+                  "          private: int n; };"
+                  "C returnC(int m) { C c(m); return c; }"
+                  "void foo() { C c = returnC(1); }"));
+}
+
+} // namespace
+} // namespace ento
+} // namespace clang
Index: clang/unittests/StaticAnalyzer/CMakeLists.txt
===================================================================
--- clang/unittests/StaticAnalyzer/CMakeLists.txt
+++ clang/unittests/StaticAnalyzer/CMakeLists.txt
@@ -10,6 +10,7 @@
   StoreTest.cpp
   RegisterCustomCheckersTest.cpp
   SymbolReaperTest.cpp
+  TestReturnValueUnderConstruction.cpp
   )
 
 clang_target_link_libraries(StaticAnalysisTests
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -124,6 +124,10 @@
     case ConstructionContext::SimpleVariableKind: {
       const auto *DSCC = cast<VariableConstructionContext>(CC);
       const auto *DS = DSCC->getDeclStmt();
+      Optional<SVal> ExistingVal = getObjectUnderConstruction(State, DS, LCtx);
+      if (ExistingVal.hasValue())
+        return std::make_pair(State, *ExistingVal);
+
       const auto *Var = cast<VarDecl>(DS->getSingleDecl());
       SVal LValue = State->getLValue(Var, LCtx);
       QualType Ty = Var->getType();
@@ -137,6 +141,11 @@
     case ConstructionContext::SimpleConstructorInitializerKind: {
       const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
       const auto *Init = ICC->getCXXCtorInitializer();
+      Optional<SVal> ExistingVal =
+        getObjectUnderConstruction(State, Init, LCtx);
+      if (ExistingVal.hasValue())
+        return std::make_pair(State, *ExistingVal);
+
       assert(Init->isAnyMemberInitializer());
       const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
       Loc ThisPtr =
@@ -235,6 +244,9 @@
       const CXXBindTemporaryExpr *BTE = TCC->getCXXBindTemporaryExpr();
       const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr();
       const CXXConstructExpr *CE = TCC->getConstructorAfterElision();
+      Optional<SVal> ExistingVal = getObjectUnderConstruction(State, CE, LCtx);
+      if (ExistingVal.hasValue())
+        return std::make_pair(State, *ExistingVal);
 
       // Support pre-C++17 copy elision. We'll have the elidable copy
       // constructor in the AST and in the CFG, but we'll skip it
@@ -281,7 +293,19 @@
       const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr();
       SVal V = UnknownVal();
 
+      if (BTE) {
+        Optional<SVal> ExistingVal =
+          getObjectUnderConstruction(State, BTE, LCtx);
+        if (ExistingVal.hasValue())
+          return std::make_pair(State, *ExistingVal);
+      }
+
       if (MTE) {
+        Optional<SVal> ExistingVal =
+          getObjectUnderConstruction(State, MTE, LCtx);
+        if (ExistingVal.hasValue())
+          return std::make_pair(State, *ExistingVal);
+
         if (const ValueDecl *VD = MTE->getExtendingDecl()) {
           assert(MTE->getStorageDuration() != SD_FullExpression);
           if (!VD->getType()->isReferenceType()) {
@@ -318,7 +342,30 @@
       const auto *ACC = cast<ArgumentConstructionContext>(CC);
       const Expr *E = ACC->getCallLikeExpr();
       unsigned Idx = ACC->getIndex();
+      if (const auto *CE = dyn_cast<CallExpr>(E)) {
+        Optional<SVal> ExistingVal =
+          getObjectUnderConstruction(State, {CE, Idx}, LCtx);
+        if (ExistingVal.hasValue())
+          return std::make_pair(State, *ExistingVal);
+      } else if (const auto *CCE = dyn_cast<CXXConstructExpr>(E)) {
+        Optional<SVal> ExistingVal =
+          getObjectUnderConstruction(State, {CCE, Idx}, LCtx);
+        if (ExistingVal.hasValue())
+          return std::make_pair(State, *ExistingVal);
+      } else if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) {
+        Optional<SVal> ExistingVal =
+          getObjectUnderConstruction(State, {ME, Idx}, LCtx);
+        if (ExistingVal.hasValue())
+          return std::make_pair(State, *ExistingVal);
+      }
+
       const CXXBindTemporaryExpr *BTE = ACC->getCXXBindTemporaryExpr();
+      if (BTE) {
+        Optional<SVal> ExistingVal =
+          getObjectUnderConstruction(State, BTE, LCtx);
+        if (ExistingVal.hasValue())
+          return std::make_pair(State, *ExistingVal);
+      }
 
       CallEventManager &CEMgr = getStateManager().getCallEventManager();
       SVal V = UnknownVal();
Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -535,6 +535,50 @@
   // FIXME: Variadic arguments are not handled at all right now.
 }
 
+static const ConstructionContext
+*getConstructionContext(const CallEvent &Call, unsigned BlockCount) {
+  const CFGBlock *Block;
+  unsigned Index;
+
+  const StackFrameContext *StackFrame = Call.getCalleeStackFrame(BlockCount);
+  if (!StackFrame)
+    return nullptr;
+
+  Block = StackFrame->getCallSiteBlock();
+  if (!Block)
+    return nullptr;
+
+  Index = StackFrame->getIndex();
+
+  if(const auto Ctor = (*Block)[Index].getAs<CFGConstructor>()) {
+    return Ctor->getConstructionContext();
+  }
+
+  if (const auto RecCall = (*Block)[Index].getAs<CFGCXXRecordTypedCall>()) {
+    return RecCall->getConstructionContext();
+  }
+
+  return nullptr;
+}
+
+Optional<SVal>
+CallEvent::getReturnValueUnderConstruction(unsigned BlockCount) const {
+  const auto *CC = getConstructionContext(*this, BlockCount);
+  if (!CC)
+    return None;
+
+  ProgramStateRef State;
+  SVal RetVal;
+  ExprEngine::EvalCallOptions CallOpts;
+  SubEngine &Engine = getState()->getStateManager().getOwningEngine();
+  std::tie(State, RetVal) =
+    static_cast<ExprEngine*>(&Engine)->handleConstructionContext(getOriginExpr(),
+                                                         getState(),
+                                                         getLocationContext(),
+                                                         CC, CallOpts);
+  return RetVal;
+}
+
 ArrayRef<ParmVarDecl*> AnyFunctionCall::parameters() const {
   const FunctionDecl *D = getDecl();
   if (!D)
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -686,6 +686,16 @@
                        const CallEvent &Call,
                        const EvalCallOptions &CallOpts = {});
 
+  /// Update the program state with all the path-sensitive information
+  /// that's necessary to perform construction of an object with a given
+  /// syntactic construction context. If the construction context is unavailable
+  /// or unusable for any reason, a dummy temporary region is returned, and the
+  /// IsConstructorWithImproperlyModeledTargetRegion flag is set in \p CallOpts.
+  /// Returns the updated program state and the new object's this-region.
+  std::pair<ProgramStateRef, SVal> handleConstructionContext(
+      const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
+      const ConstructionContext *CC, EvalCallOptions &CallOpts);
+
 private:
   ProgramStateRef finishArgumentConstruction(ProgramStateRef State,
                                              const CallEvent &Call);
@@ -804,16 +814,6 @@
   /// constructing into an existing region.
   const CXXConstructExpr *findDirectConstructorForCurrentCFGElement();
 
-  /// Update the program state with all the path-sensitive information
-  /// that's necessary to perform construction of an object with a given
-  /// syntactic construction context. If the construction context is unavailable
-  /// or unusable for any reason, a dummy temporary region is returned, and the
-  /// IsConstructorWithImproperlyModeledTargetRegion flag is set in \p CallOpts.
-  /// Returns the updated program state and the new object's this-region.
-  std::pair<ProgramStateRef, SVal> handleConstructionContext(
-      const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
-      const ConstructionContext *CC, EvalCallOptions &CallOpts);
-
   /// Common code that handles either a CXXConstructExpr or a
   /// CXXInheritedCtorInitExpr.
   void handleConstructor(const Expr *E, ExplodedNode *Pred,
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -434,6 +434,10 @@
     return CallArgumentIndex;
   }
 
+  /// If the call returns a C++ record type then the region of its return value
+  // can be retrieved from its construction context.
+  Optional<SVal> getReturnValueUnderConstruction(unsigned BlockCount) const;
+
   // Iterator access to formal parameters and their types.
 private:
   struct GetTypeFn {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to