baloghadamsoftware created this revision.
baloghadamsoftware added reviewers: NoQ, Szelethus, martong, balazske.
baloghadamsoftware added a project: clang.
Herald added subscribers: ASDenysPetrov, steakhal, Charusso, gamesh411, dkrupp, 
donat.nagy, mikhail.ramalho, a.sidorin, rnkovacs, szepet, xazax.hun, 
whisperity, mgorny.

Currently, parameters of functions without their definition present cannot be 
represented as regions because it would be difficult to ensure that the same 
declaration is used in every case. To overcome this, we split `VarRegion` to 
two subclasses: `NonParamVarRegion` and `ParamVarRegion`. The latter does not 
store the `Decl` of the parameter variable. Instead it stores the index of the 
parameter which enables retrieving the actual `Decl` every time using the 
function declaration of the stack frame. To achieve this we also removed 
storing of `Decl` from `DeclRegion` and made `getDecl()` pure virtual. The 
individual `Decl`s are stored in the appropriate subclasses, such as 
`FieldRegion`, `ObjCIvarRegion` and the newly introduced `NonParamVarRegion`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D80522

Files:
  clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
  clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
  clang/lib/StaticAnalyzer/Core/CallEvent.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
  clang/lib/StaticAnalyzer/Core/MemRegion.cpp
  clang/lib/StaticAnalyzer/Core/Store.cpp
  clang/test/Analysis/explain-svals.c
  clang/test/Analysis/explain-svals.cpp
  clang/test/Analysis/explain-svals.m
  clang/unittests/StaticAnalyzer/CMakeLists.txt
  clang/unittests/StaticAnalyzer/ParamRegionTest.cpp

Index: clang/unittests/StaticAnalyzer/ParamRegionTest.cpp
===================================================================
--- /dev/null
+++ clang/unittests/StaticAnalyzer/ParamRegionTest.cpp
@@ -0,0 +1,92 @@
+//===- unittests/StaticAnalyzer/ParamRegionTest.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 "Reusables.h"
+
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ento {
+namespace {
+
+class ParamRegionTestConsumer : public ExprEngineConsumer {
+  void performTest(const Decl *D) {
+    StoreManager &StMgr = Eng.getStoreManager();
+    MemRegionManager &MRMgr = StMgr.getRegionManager();
+    const StackFrameContext *SFC =
+        Eng.getAnalysisDeclContextManager().getStackFrame(D);
+
+    if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+      for (const auto *P : FD->parameters()) {
+        const TypedValueRegion *Reg = MRMgr.getVarRegion(P, SFC);
+        if (SFC->inTopFrame())
+          assert(isa<NonParamVarRegion>(Reg));
+        else
+          assert(isa<ParamVarRegion>(Reg));
+      }
+    } else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
+      for (const auto *P : CD->parameters()) {
+        const TypedValueRegion *Reg = MRMgr.getVarRegion(P, SFC);
+        if (SFC->inTopFrame())
+          assert(isa<NonParamVarRegion>(Reg));
+        else
+          assert(isa<ParamVarRegion>(Reg));
+      }
+    } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+      for (const auto *P : MD->parameters()) {
+        const TypedValueRegion *Reg = MRMgr.getVarRegion(P, SFC);
+        if (SFC->inTopFrame())
+          assert(isa<NonParamVarRegion>(Reg));
+        else
+          assert(isa<ParamVarRegion>(Reg));
+      }
+    }
+  }
+
+public:
+  ParamRegionTestConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
+
+  bool HandleTopLevelDecl(DeclGroupRef DG) override {
+    for (const auto *D : DG) {
+      performTest(D);
+    }
+    return true;
+  }
+};
+
+class ParamRegionTestAction : public ASTFrontendAction {
+public:
+  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
+                                                 StringRef File) override {
+    return std::make_unique<ParamRegionTestConsumer>(Compiler);
+  }
+};
+
+TEST(ParamRegion, ParamRegionTest) {
+  EXPECT_TRUE(tooling::runToolOnCode(
+                  std::make_unique<ParamRegionTestAction>(),
+                  "void foo(int n) { "
+                  "auto lambda = [n](int m) { return n + m; }; "
+                  "int k = lambda(2); } "
+                  "void bar(int l) { foo(l); }"
+                  "struct S { int n; S(int nn): n(nn) {} };"
+                  "void baz(int p) { S s(p); }"));
+  EXPECT_TRUE(tooling::runToolOnCode(
+                  std::make_unique<ParamRegionTestAction>(),
+                  "@interface O \n"
+                  "+alloc; \n"
+                  "-initWithInt:(int)q; \n"
+                  "@end \n"
+                  "void qix(int r) { O *o = [[O alloc] initWithInt:r]; }",
+                  "input.m"));
+}
+
+} // namespace
+} // namespace ento
+} // namespace clang
Index: clang/unittests/StaticAnalyzer/CMakeLists.txt
===================================================================
--- clang/unittests/StaticAnalyzer/CMakeLists.txt
+++ clang/unittests/StaticAnalyzer/CMakeLists.txt
@@ -8,6 +8,7 @@
   CallDescriptionTest.cpp
   CallEventTest.cpp
   StoreTest.cpp
+  ParamRegionTest.cpp
   RegisterCustomCheckersTest.cpp
   SymbolReaperTest.cpp
   )
Index: clang/test/Analysis/explain-svals.m
===================================================================
--- clang/test/Analysis/explain-svals.m
+++ clang/test/Analysis/explain-svals.m
@@ -28,3 +28,44 @@
   };
   clang_analyzer_explain(&x); // expected-warning-re{{{{^pointer to block variable 'x'$}}}}
 }
+
+@interface O
++(instancetype)top_level_class_method:(int)param;
++(instancetype)non_top_level_class_method:(int)param;
+-top_level_instance_method:(int)param;
+-non_top_level_instance_method:(int)param;
+@end
+
+@implementation O
++(instancetype)top_level_class_method:(int)param {
+  clang_analyzer_explain(&param); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+}
+
++(instancetype)non_top_level_class_method:(int)param {
+  clang_analyzer_explain(&param); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+}
+
+-top_level_instance_method:(int)param {
+  clang_analyzer_explain(&param); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+}
+
+-non_top_level_instance_method:(int)param {
+  clang_analyzer_explain(&param); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+}
+@end
+
+void test_3(int n, int m) {
+  O* o = [O non_top_level_class_method:n];
+  [o non_top_level_instance_method:m];
+
+void (^block_top_level)(int) = ^(int param){
+    clang_analyzer_explain(&param); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+    clang_analyzer_explain(&n); // expected-warning-re{{{{^pointer to parameter 'n'$}}}}
+  };
+void (^block_non_top_level)(int) = ^(int param){
+    clang_analyzer_explain(&param); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+    clang_analyzer_explain(&n); // expected-warning-re{{{{^pointer to parameter 'n'$}}}}
+  };
+
+  block_non_top_level(n);
+}
Index: clang/test/Analysis/explain-svals.cpp
===================================================================
--- clang/test/Analysis/explain-svals.cpp
+++ clang/test/Analysis/explain-svals.cpp
@@ -19,6 +19,7 @@
 
 void clang_analyzer_explain(int);
 void clang_analyzer_explain(void *);
+void clang_analyzer_explain(const int *);
 void clang_analyzer_explain(S);
 
 size_t clang_analyzer_getExtent(void *);
@@ -100,3 +101,30 @@
   clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^lazily frozen compound value of temporary object constructed at statement 'conjure_S\(\)'$}}}}
   clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure_S\(\)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}}
 }
+
+class C_top_level {
+public:
+  C_top_level(int param) {
+    clang_analyzer_explain(&param); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+  }
+};
+
+class C_non_top_level {
+public:
+  C_non_top_level(int param) {
+    clang_analyzer_explain(&param); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+  }
+};
+
+void test_7(int n) {
+  C_non_top_level c(n);
+
+  auto lambda_top_level = [n](int param) {
+    clang_analyzer_explain(&param); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+  };
+  auto lambda_non_top_level = [n](int param) {
+    clang_analyzer_explain(&param); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+  };
+
+  lambda_non_top_level(n);
+}
Index: clang/test/Analysis/explain-svals.c
===================================================================
--- clang/test/Analysis/explain-svals.c
+++ clang/test/Analysis/explain-svals.c
@@ -27,3 +27,15 @@
   clang_analyzer_explain_voidp(&s); // expected-warning-re{{{{^pointer to parameter 's'$}}}}
   clang_analyzer_explain_int(s.z);  // expected-warning-re{{{{^initial value of field 'z' of parameter 's'$}}}}
 }
+
+void test_3(int param) {
+  clang_analyzer_explain_voidp(&param); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+}
+
+void test_non_top_level(int param) {
+  clang_analyzer_explain_voidp(&param); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+}
+
+void test_4(int n) {
+  test_non_top_level(n);
+}
Index: clang/lib/StaticAnalyzer/Core/Store.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/Store.cpp
+++ clang/lib/StaticAnalyzer/Core/Store.cpp
@@ -134,7 +134,8 @@
     case MemRegion::FieldRegionKind:
     case MemRegion::ObjCIvarRegionKind:
     case MemRegion::ObjCStringRegionKind:
-    case MemRegion::VarRegionKind:
+    case MemRegion::NonParamVarRegionKind:
+    case MemRegion::ParamVarRegionKind:
     case MemRegion::CXXTempObjectRegionKind:
     case MemRegion::CXXBaseObjectRegionKind:
     case MemRegion::CXXDerivedObjectRegionKind:
Index: clang/lib/StaticAnalyzer/Core/MemRegion.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -160,10 +160,10 @@
 }
 
 ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg)
-    : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
+    : DeclRegion(sReg, ObjCIvarRegionKind), IVD(ivd) {}
 
 const ObjCIvarDecl *ObjCIvarRegion::getDecl() const {
-  return cast<ObjCIvarDecl>(D);
+  return IVD;
 }
 
 QualType ObjCIvarRegion::getValueType() const {
@@ -178,6 +178,32 @@
   return QualType(getDecl()->getTypeForDecl(), 0);
 }
 
+QualType ParamVarRegion::getValueType() const {
+  assert (getDecl() &&
+          "`ParamVarRegion` does not support functions without `Decl`");
+  return getDecl()->getType();
+}
+
+const ParmVarDecl *ParamVarRegion::getDecl() const {
+  const Decl *D = getStackFrame()->getDecl();
+
+  if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+    assert (Index < FD->param_size());
+    return FD->parameters()[Index];
+  } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
+    assert (Index < BD->param_size());
+    return BD->parameters()[Index];
+  } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+    assert (Index < MD->param_size());
+    return MD->parameters()[Index];
+  } else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
+    assert (Index < CD->param_size());
+    return CD->parameters()[Index];
+  } else {
+    llvm_unreachable("Unexpected Decl kind!");
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // FoldingSet profiling.
 //===----------------------------------------------------------------------===//
@@ -249,25 +275,44 @@
   CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion);
 }
 
+void FieldRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, getDecl(), superRegion);
+}
+
 void ObjCIvarRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
                                    const ObjCIvarDecl *ivd,
                                    const MemRegion* superRegion) {
-  DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind);
+  ID.AddInteger(static_cast<unsigned>(ObjCIvarRegionKind));
+  ID.AddPointer(ivd);
+  ID.AddPointer(superRegion);
 }
 
-void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D,
-                               const MemRegion* superRegion, Kind k) {
-  ID.AddInteger(static_cast<unsigned>(k));
-  ID.AddPointer(D);
+void ObjCIvarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, getDecl(), superRegion);
+}
+
+void NonParamVarRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                      const VarDecl *VD,
+                                      const MemRegion *superRegion) {
+  ID.AddInteger(static_cast<unsigned>(NonParamVarRegionKind));
+  ID.AddPointer(VD);
   ID.AddPointer(superRegion);
 }
 
-void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const {
-  DeclRegion::ProfileRegion(ID, D, superRegion, getKind());
+void NonParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, getDecl(), superRegion);
+}
+
+void ParamVarRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, const Expr *OE,
+                                unsigned Idx, const MemRegion *SReg) {
+  ID.AddInteger(static_cast<unsigned>(ParamVarRegionKind));
+  ID.AddPointer(OE);
+  ID.AddInteger(Idx);
+  ID.AddPointer(SReg);
 }
 
-void VarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
-  VarRegion::ProfileRegion(ID, getDecl(), superRegion);
+void ParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, getOriginExpr(), getIndex(), superRegion);
 }
 
 void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym,
@@ -479,12 +524,11 @@
   os << "SymRegion{" << sym << '}';
 }
 
-void VarRegion::dumpToStream(raw_ostream &os) const {
-  const auto *VD = cast<VarDecl>(D);
+void NonParamVarRegion::dumpToStream(raw_ostream &os) const {
   if (const IdentifierInfo *ID = VD->getIdentifier())
     os << ID->getName();
   else
-    os << "VarRegion{D" << VD->getID() << '}';
+    os << "NonParamVarRegion{D" << VD->getID() << '}';
 }
 
 LLVM_DUMP_METHOD void RegionRawOffset::dump() const {
@@ -531,6 +575,17 @@
   os << "StackLocalsSpaceRegion";
 }
 
+void ParamVarRegion::dumpToStream(raw_ostream &os) const {
+  const ParmVarDecl *PVD = getDecl();
+  assert (PVD &&
+          "`ParamVarRegion` does not support functions without `Decl`");
+  if (const IdentifierInfo *ID = PVD->getIdentifier()) {
+    os << ID->getName();
+  } else {
+    os << "ParamVarRegion{P" << PVD->getID() << '}';
+  }
+}
+
 bool MemRegion::canPrintPretty() const {
   return canPrintPrettyAsExpr();
 }
@@ -550,11 +605,11 @@
   llvm_unreachable("This region cannot be printed pretty.");
 }
 
-bool VarRegion::canPrintPrettyAsExpr() const {
+bool NonParamVarRegion::canPrintPrettyAsExpr() const {
   return true;
 }
 
-void VarRegion::printPrettyAsExpr(raw_ostream &os) const {
+void NonParamVarRegion::printPrettyAsExpr(raw_ostream &os) const {
   os << getDecl()->getName();
 }
 
@@ -606,6 +661,16 @@
   superRegion->printPrettyAsExpr(os);
 }
 
+bool ParamVarRegion::canPrintPrettyAsExpr() const {
+  return true;
+}
+
+void ParamVarRegion::printPrettyAsExpr(raw_ostream &os) const {
+  assert (getDecl() &&
+          "`ParamVarRegion` does not support functions without `Decl`");
+  os << getDecl()->getName();
+}
+
 std::string MemRegion::getDescriptiveName(bool UseQuotes) const {
   std::string VariableName;
   std::string ArrayIndices;
@@ -693,7 +758,8 @@
   case MemRegion::CXXTempObjectRegionKind:
   case MemRegion::CXXThisRegionKind:
   case MemRegion::ObjCIvarRegionKind:
-  case MemRegion::VarRegionKind:
+  case MemRegion::NonParamVarRegionKind:
+  case MemRegion::ParamVarRegionKind:
   case MemRegion::ElementRegionKind:
   case MemRegion::ObjCStringRegionKind: {
     QualType Ty = cast<TypedValueRegion>(SR)->getDesugaredValueType(Ctx);
@@ -847,9 +913,11 @@
       for (BlockDataRegion::referenced_vars_iterator
            I = BR->referenced_vars_begin(),
            E = BR->referenced_vars_end(); I != E; ++I) {
-        const VarRegion *VR = I.getOriginalRegion();
-        if (VR->getDecl() == VD)
-          return cast<VarRegion>(I.getCapturedRegion());
+        const TypedValueRegion *OrigR = I.getOriginalRegion();
+        if (const auto *VR = dyn_cast<VarRegion>(OrigR)) {
+          if (VR->getDecl() == VD)
+            return cast<VarRegion>(I.getCapturedRegion());
+        }
       }
     }
 
@@ -858,8 +926,31 @@
   return (const StackFrameContext *)nullptr;
 }
 
-const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
-                                                const LocationContext *LC) {
+const VarRegion*
+MemRegionManager::getVarRegion(const VarDecl *D,
+                               const LocationContext *LC) {
+  const auto *PVD = dyn_cast<ParmVarDecl>(D);
+  if (PVD) {
+    unsigned Index = PVD->getFunctionScopeIndex();
+    const StackFrameContext *SFC = LC->getStackFrame();
+    const Stmt *CallSite = SFC->getCallSite();
+    if (CallSite) {
+      const Decl *D = SFC->getDecl();
+      if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+        if (Index < FD->param_size() && FD->parameters()[Index] == PVD)
+          return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
+                                              getStackArgumentsRegion(SFC));
+      } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
+        if (Index < BD->param_size() && BD->parameters()[Index] == PVD)
+          return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
+                                              getStackArgumentsRegion(SFC));
+      } else {
+        return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
+                                            getStackArgumentsRegion(SFC));
+      }
+    }
+  }
+
   D = D->getCanonicalDecl();
   const MemRegion *sReg = nullptr;
 
@@ -942,13 +1033,24 @@
     }
   }
 
-  return getSubRegion<VarRegion>(D, sReg);
+  return getSubRegion<NonParamVarRegion>(D, sReg);
 }
 
-const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,
-                                                const MemRegion *superR) {
+const NonParamVarRegion
+*MemRegionManager::getNonParamVarRegion(const VarDecl *D,
+                                        const MemRegion *superR) {
   D = D->getCanonicalDecl();
-  return getSubRegion<VarRegion>(D, superR);
+  return getSubRegion<NonParamVarRegion>(D, superR);
+}
+
+const ParamVarRegion
+*MemRegionManager::getParamVarRegion(const Expr *OriginExpr,
+                                     unsigned Index,
+                                     const LocationContext *LC) {
+  const StackFrameContext *SFC = LC->getStackFrame();
+  assert(SFC);
+  return getSubRegion<ParamVarRegion>(OriginExpr, Index,
+                                      getStackArgumentsRegion(SFC));
 }
 
 const BlockDataRegion *
@@ -1341,7 +1443,8 @@
     case MemRegion::CXXThisRegionKind:
     case MemRegion::StringRegionKind:
     case MemRegion::ObjCStringRegionKind:
-    case MemRegion::VarRegionKind:
+    case MemRegion::NonParamVarRegionKind:
+    case MemRegion::ParamVarRegionKind:
     case MemRegion::CXXTempObjectRegionKind:
       // Usual base regions.
       goto Finish;
@@ -1497,7 +1600,7 @@
   const VarRegion *OriginalVR = nullptr;
 
   if (!VD->hasAttr<BlocksAttr>() && VD->hasLocalStorage()) {
-    VR = MemMgr.getVarRegion(VD, this);
+    VR = MemMgr.getNonParamVarRegion(VD, this);
     OriginalVR = MemMgr.getVarRegion(VD, LC);
   }
   else {
@@ -1506,7 +1609,7 @@
       OriginalVR = VR;
     }
     else {
-      VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion());
+      VR = MemMgr.getNonParamVarRegion(VD, MemMgr.getUnknownRegion());
       OriginalVR = MemMgr.getVarRegion(VD, LC);
     }
   }
@@ -1584,7 +1687,8 @@
                                                    VecOriginal->end());
 }
 
-const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
+const VarRegion
+*BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
   for (referenced_vars_iterator I = referenced_vars_begin(),
                                 E = referenced_vars_end();
        I != E; ++I) {
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -536,9 +536,11 @@
             getObjectUnderConstruction(State, {E, I}, LC)) {
       SVal VV = *V;
       (void)VV;
-      assert(cast<VarRegion>(VV.castAs<loc::MemRegionVal>().getRegion())
-                 ->getStackFrame()->getParent()
-                 ->getStackFrame() == LC->getStackFrame());
+      if (const auto *VR =
+          dyn_cast<VarRegion>(VV.castAs<loc::MemRegionVal>().getRegion())) {
+        assert(VR->getStackFrame()->getParent()
+               ->getStackFrame() == LC->getStackFrame());
+      }
       State = finishObjectConstruction(State, {E, I}, LC);
     }
   }
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -342,12 +342,12 @@
         // Operator arguments do not correspond to operator parameters
         // because this-argument is implemented as a normal argument in
         // operator call expressions but not in operator declarations.
-        const VarRegion *VR = Caller->getParameterLocation(
+        const TypedValueRegion *TVR = Caller->getParameterLocation(
             *Caller->getAdjustedParameterIndex(Idx), currBldrCtx->blockCount());
-        if (!VR)
+        if (!TVR)
           return None;
 
-        return loc::MemRegionVal(VR);
+        return loc::MemRegionVal(TVR);
       };
 
       if (const auto *CE = dyn_cast<CallExpr>(E)) {
Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -218,7 +218,7 @@
     auto CE = BD->capture_end();
     for (; I != E; ++I) {
       const VarRegion *capturedR = I.getCapturedRegion();
-      const VarRegion *originalR = I.getOriginalRegion();
+      const TypedValueRegion *originalR = I.getOriginalRegion();
 
       // If the capture had a copy expression, use the result of evaluating
       // that expression, otherwise use the original value.
Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -222,39 +222,19 @@
   return ADC->getManager()->getStackFrame(ADC, LCtx, E, B, BlockCount, Idx);
 }
 
-const VarRegion *CallEvent::getParameterLocation(unsigned Index,
-                                                 unsigned BlockCount) const {
+const ParamVarRegion
+*CallEvent::getParameterLocation(unsigned Index,
+                                 unsigned BlockCount) const {
   const StackFrameContext *SFC = getCalleeStackFrame(BlockCount);
   // We cannot construct a VarRegion without a stack frame.
   if (!SFC)
     return nullptr;
 
-  // Retrieve parameters of the definition, which are different from
-  // CallEvent's parameters() because getDecl() isn't necessarily
-  // the definition. SFC contains the definition that would be used
-  // during analysis.
-  const Decl *D = SFC->getDecl();
-
-  // TODO: Refactor into a virtual method of CallEvent, like parameters().
-  const ParmVarDecl *PVD = nullptr;
-  if (const auto *FD = dyn_cast<FunctionDecl>(D))
-    PVD = FD->parameters()[Index];
-  else if (const auto *BD = dyn_cast<BlockDecl>(D))
-    PVD = BD->parameters()[Index];
-  else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
-    PVD = MD->parameters()[Index];
-  else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D))
-    PVD = CD->parameters()[Index];
-  assert(PVD && "Unexpected Decl kind!");
-
-  const VarRegion *VR =
-      State->getStateManager().getRegionManager().getVarRegion(PVD, SFC);
-
-  // This sanity check would fail if our parameter declaration doesn't
-  // correspond to the stack frame's function declaration.
-  assert(VR->getStackFrame() == SFC);
-
-  return VR;
+  const ParamVarRegion *PVR =
+    State->
+      getStateManager().getRegionManager().getParamVarRegion(getOriginExpr(),
+                                                             Index, SFC);
+  return PVR;
 }
 
 /// Returns true if a type is a pointer-to-const or reference-to-const
@@ -325,8 +305,9 @@
     if (getKind() != CE_CXXAllocator)
       if (isArgumentConstructedDirectly(Idx))
         if (auto AdjIdx = getAdjustedParameterIndex(Idx))
-          if (const VarRegion *VR = getParameterLocation(*AdjIdx, BlockCount))
-            ValuesToInvalidate.push_back(loc::MemRegionVal(VR));
+          if (const TypedValueRegion *TVR =
+              getParameterLocation(*AdjIdx, BlockCount))
+            ValuesToInvalidate.push_back(loc::MemRegionVal(TVR));
   }
 
   // Invalidate designated regions using the batch invalidation API.
@@ -527,7 +508,9 @@
     // which makes getArgSVal() fail and return UnknownVal.
     SVal ArgVal = Call.getArgSVal(Idx);
     if (!ArgVal.isUnknown()) {
-      Loc ParamLoc = SVB.makeLoc(MRMgr.getVarRegion(ParamDecl, CalleeCtx));
+      Loc ParamLoc =
+        SVB.makeLoc(MRMgr.getParamVarRegion(Call.getOriginExpr(), Idx,
+                                            CalleeCtx));
       Bindings.push_back(std::make_pair(ParamLoc, ArgVal));
     }
   }
Index: clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -709,7 +709,8 @@
 
   case MemRegion::SymbolicRegionKind:
   case MemRegion::AllocaRegionKind:
-  case MemRegion::VarRegionKind:
+  case MemRegion::NonParamVarRegionKind:
+  case MemRegion::ParamVarRegionKind:
   case MemRegion::FieldRegionKind:
   case MemRegion::ObjCIvarRegionKind:
     // These are the types we can currently track string lengths for.
@@ -814,7 +815,8 @@
   }
   case MemRegion::SymbolicRegionKind:
   case MemRegion::AllocaRegionKind:
-  case MemRegion::VarRegionKind:
+  case MemRegion::NonParamVarRegionKind:
+  case MemRegion::ParamVarRegionKind:
   case MemRegion::FieldRegionKind:
   case MemRegion::ObjCIvarRegionKind:
     return getCStringLengthForRegion(C, state, Ex, MR, hypothetical);
@@ -1009,10 +1011,14 @@
     os << "a C++ temp object of type "
        << cast<TypedValueRegion>(MR)->getValueType().getAsString();
     return true;
-  case MemRegion::VarRegionKind:
+  case MemRegion::NonParamVarRegionKind:
     os << "a variable of type"
        << cast<TypedValueRegion>(MR)->getValueType().getAsString();
     return true;
+  case MemRegion::ParamVarRegionKind:
+    os << "a parameter of type"
+       << cast<TypedValueRegion>(MR)->getValueType().getAsString();
+    return true;
   case MemRegion::FieldRegionKind:
     os << "a field of type "
        << cast<TypedValueRegion>(MR)->getValueType().getAsString();
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
@@ -73,9 +73,13 @@
       ABSTRACT_REGION(DeclRegion, TypedValueRegion)
         REGION(FieldRegion, DeclRegion)
         REGION(ObjCIvarRegion, DeclRegion)
-        REGION(VarRegion, DeclRegion)
-        REGION_RANGE(DECL_REGIONS, FieldRegionKind,
-                                   VarRegionKind)
+        ABSTRACT_REGION(VarRegion, DeclRegion)
+          REGION(NonParamVarRegion, VarRegion)
+          REGION(ParamVarRegion, VarRegion)
+        REGION_RANGE(VAR_REGIONS, NonParamVarRegionKind,
+                                  ParamVarRegionKind)
+      REGION_RANGE(DECL_REGIONS, FieldRegionKind,
+                                 ParamVarRegionKind)
       REGION(ElementRegion, TypedValueRegion)
       REGION(ObjCStringRegion, TypedValueRegion)
       REGION(StringRegion, TypedValueRegion)
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -308,6 +308,10 @@
   Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super,
                 bool IsVirtual) const;
 
+  /// Get the lvalue for a parameter.
+  Loc getLValue(const Expr *Call, unsigned Index,
+                const LocationContext *LC) const;
+
   /// Get the lvalue for a variable reference.
   Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
 
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -890,20 +890,13 @@
 
 class DeclRegion : public TypedValueRegion {
 protected:
-  const ValueDecl *D;
-
-  DeclRegion(const ValueDecl *d, const MemRegion *sReg, Kind k)
-      : TypedValueRegion(sReg, k), D(d) {
+  DeclRegion(const MemRegion *sReg, Kind k)
+      : TypedValueRegion(sReg, k) {
     assert(classof(this));
-    assert(d && d->isCanonicalDecl());
   }
 
-  static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D,
-                      const MemRegion* superRegion, Kind k);
-
 public:
-  const ValueDecl *getDecl() const { return D; }
-  void Profile(llvm::FoldingSetNodeID& ID) const override;
+  virtual const ValueDecl *getDecl() const = 0;
 
   static bool classof(const MemRegion* R) {
     unsigned k = R->getKind();
@@ -914,9 +907,42 @@
 class VarRegion : public DeclRegion {
   friend class MemRegionManager;
 
+protected:
+  // Constructors and protected methods.
+  VarRegion(const MemRegion *sReg, Kind k)
+      : DeclRegion(sReg, k) {
+    // VarRegion appears in unknown space when it's a block variable as seen
+    // from a block using it, when this block is analyzed at top-level.
+    // Other block variables appear within block data regions,
+    // which, unlike everything else on this list, are not memory spaces.
+    assert(isa<GlobalsSpaceRegion>(sReg) || isa<StackSpaceRegion>(sReg) ||
+           isa<BlockDataRegion>(sReg) || isa<UnknownSpaceRegion>(sReg));
+  }
+
+public:
+  const VarDecl *getDecl() const override = 0;
+
+  const StackFrameContext *getStackFrame() const;
+
+  QualType getValueType() const override {
+    // FIXME: We can cache this if needed.
+    return getDecl()->getType();
+  }
+
+  static bool classof(const MemRegion* R) {
+    unsigned k = R->getKind();
+    return k >= BEGIN_VAR_REGIONS && k <= END_VAR_REGIONS;
+  }
+};
+
+class NonParamVarRegion : public VarRegion {
+  friend class MemRegionManager;
+
+  const VarDecl *VD;
+
   // Constructors and private methods.
-  VarRegion(const VarDecl *vd, const MemRegion *sReg)
-      : DeclRegion(vd, sReg, VarRegionKind) {
+  NonParamVarRegion(const VarDecl *vd, const MemRegion *sReg)
+      : VarRegion(sReg, NonParamVarRegionKind), VD(vd) {
     // VarRegion appears in unknown space when it's a block variable as seen
     // from a block using it, when this block is analyzed at top-level.
     // Other block variables appear within block data regions,
@@ -926,16 +952,12 @@
   }
 
   static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD,
-                            const MemRegion *superRegion) {
-    DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
-  }
+                            const MemRegion *superRegion);
 
 public:
   void Profile(llvm::FoldingSetNodeID& ID) const override;
 
-  const VarDecl *getDecl() const { return cast<VarDecl>(D); }
-
-  const StackFrameContext *getStackFrame() const;
+  const VarDecl *getDecl() const override { return VD; }
 
   QualType getValueType() const override {
     // FIXME: We can cache this if needed.
@@ -949,7 +971,49 @@
   void printPrettyAsExpr(raw_ostream &os) const override;
 
   static bool classof(const MemRegion* R) {
-    return R->getKind() == VarRegionKind;
+    return R->getKind() == NonParamVarRegionKind;
+  }
+};
+
+/// ParamVarRegion - Represents a region for paremters. Only parameters of the
+/// function in the current stack frame are represented as `ParamVarRegion`s.
+/// Parameters of top-level analyzed functions as well as captured paremeters
+/// by lambdas and blocks are repesented as `VarRegion`s.
+
+// FIXME: `ParamVarRegion` only supports parameters of functions, C++
+// constructors, blocks and Objective-C methods with existing `Decl`. Upon
+// implementing stack frame creations for functions without decl (functions
+// passed by function pointer) methods of `ParamVarRegion` must be updated.
+class ParamVarRegion : public VarRegion {
+  friend class MemRegionManager;
+
+  const Expr *OriginExpr;
+  unsigned Index;
+
+  ParamVarRegion(const Expr *OE, unsigned Idx, const MemRegion *SReg)
+      : VarRegion(SReg, ParamVarRegionKind), OriginExpr(OE), Index(Idx) {
+    assert(!cast<StackSpaceRegion>(SReg)->getStackFrame()->inTopFrame());
+  }
+
+  static void ProfileRegion(llvm::FoldingSetNodeID &ID, const Expr *OE,
+                            unsigned Idx, const MemRegion *SReg);
+
+public:
+  const Expr *getOriginExpr() const { return OriginExpr; }
+  unsigned getIndex() const { return Index; }
+
+  void Profile(llvm::FoldingSetNodeID& ID) const override;
+
+  void dumpToStream(raw_ostream &os) const override;
+
+  QualType getValueType() const override;
+  const ParmVarDecl* getDecl() const override;
+
+  bool canPrintPrettyAsExpr() const override;
+  void printPrettyAsExpr(raw_ostream &os) const override;
+
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == ParamVarRegionKind;
   }
 };
 
@@ -991,16 +1055,22 @@
 class FieldRegion : public DeclRegion {
   friend class MemRegionManager;
 
+  const FieldDecl *FD;
+
   FieldRegion(const FieldDecl *fd, const SubRegion* sReg)
-      : DeclRegion(fd, sReg, FieldRegionKind) {}
+      : DeclRegion(sReg, FieldRegionKind), FD(fd) {}
 
   static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD,
                             const MemRegion* superRegion) {
-    DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
+    ID.AddInteger(static_cast<unsigned>(FieldRegionKind));
+    ID.AddPointer(FD);
+    ID.AddPointer(superRegion);
   }
 
 public:
-  const FieldDecl *getDecl() const { return cast<FieldDecl>(D); }
+  const FieldDecl *getDecl() const override { return FD; }
+
+  void Profile(llvm::FoldingSetNodeID& ID) const override;
 
   QualType getValueType() const override {
     // FIXME: We can cache this if needed.
@@ -1022,6 +1092,8 @@
 class ObjCIvarRegion : public DeclRegion {
   friend class MemRegionManager;
 
+  const ObjCIvarDecl *IVD;
+
   ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg);
 
   static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd,
@@ -1029,6 +1101,9 @@
 
 public:
   const ObjCIvarDecl *getDecl() const;
+
+  void Profile(llvm::FoldingSetNodeID& ID) const override;
+
   QualType getValueType() const override;
 
   bool canPrintPrettyAsExpr() const override;
@@ -1312,11 +1387,19 @@
 
   /// getVarRegion - Retrieve or create the memory region associated with
   ///  a specified VarDecl and LocationContext.
-  const VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC);
+  const VarRegion *getVarRegion(const VarDecl *VD,
+                                const LocationContext *LC);
 
   /// getVarRegion - Retrieve or create the memory region associated with
-  ///  a specified VarDecl and super region.
-  const VarRegion *getVarRegion(const VarDecl *D, const MemRegion *superR);
+  ///  a specified VarDecl and LocationContext.
+  const NonParamVarRegion *getNonParamVarRegion(const VarDecl *VD,
+                                                const MemRegion *superR);
+
+  /// getParamVarRegion - Retrieve or create the memory region
+  /// associated with a specified CallExpr, Index and LocationContext.
+  const ParamVarRegion *getParamVarRegion(const Expr *OriginExpr,
+                                          unsigned Index,
+                                          const LocationContext *LC);
 
   /// getElementRegion - Retrieve the memory region associated with the
   ///  associated element type, index, and super region.
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
@@ -403,8 +403,8 @@
 
   /// Returns memory location for a parameter variable within the callee stack
   /// frame. May fail; returns null on failure.
-  const VarRegion *getParameterLocation(unsigned Index,
-                                        unsigned BlockCount) const;
+  const ParamVarRegion *getParameterLocation(unsigned Index,
+                                             unsigned BlockCount) const;
 
   /// Returns true if on the current path, the argument was constructed by
   /// calling a C++ constructor over it. This is an internal detail of the
Index: clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
+++ clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -179,7 +179,7 @@
     return OS.str();
   }
 
-  std::string VisitVarRegion(const VarRegion *R) {
+  std::string VisitNonParamVarRegion(const NonParamVarRegion *R) {
     const VarDecl *VD = R->getDecl();
     std::string Name = VD->getQualifiedNameAsString();
     if (isa<ParmVarDecl>(VD))
@@ -216,6 +216,48 @@
            "' inside " + Visit(R->getSuperRegion());
   }
 
+  std::string VisitParamVarRegion(const ParamVarRegion *R) {
+    std::string Str;
+    llvm::raw_string_ostream OS(Str);
+
+    const ParmVarDecl *PVD = R->getDecl();
+    std::string Name = PVD->getQualifiedNameAsString();
+    if (!Name.empty()) {
+      OS << "parameter '" << Name << "'";
+      return std::string(OS.str());
+    }
+
+    unsigned Index = R->getIndex() + 1;
+    OS << Index;
+    if (Index % 10 == 1 && Index != 11)
+      OS << "st ";
+    else if (Index % 10 == 2 && Index != 12)
+      OS << "nd ";
+    else if (Index % 10 == 3 && Index != 13)
+      OS << "rd ";
+    else
+      OS << "th ";
+    OS << "of ";
+    const Decl *Parent = R->getStackFrame()->getDecl();
+    if (const auto *FD = dyn_cast<FunctionDecl>(Parent))
+      OS <<"function '" << FD->getQualifiedNameAsString() << "()'";
+    else if (const auto *CD = dyn_cast<CXXConstructorDecl>(Parent))
+      OS <<"C++ constructor '" << CD->getQualifiedNameAsString() << "()'";
+    else if (const auto *MD = dyn_cast<ObjCMethodDecl>(Parent)) {
+      if (MD->isClassMethod())
+        OS <<"Objective-C method '+" << MD->getQualifiedNameAsString() << "'";
+      else
+        OS <<"Objective-C method '-" << MD->getQualifiedNameAsString() << "'";
+    } else if (isa<BlockDecl>(Parent)) {
+      if (cast<BlockDecl>(Parent)->isConversionFromLambda())
+        OS <<"lambda";
+      else
+        OS <<"block";
+    }
+
+    return std::string(OS.str());
+  }
+
   std::string VisitSVal(SVal V) {
     std::string Str;
     llvm::raw_string_ostream OS(Str);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to