This revision was automatically updated to reflect the committed changes.
Closed by commit rG98db1f990fc2: [Analyzer] [NFC] Parameter Regions (authored 
by baloghadamsoftware).

Changed prior to commit:
  https://reviews.llvm.org/D80522?vs=268131&id=269477#toc

Repository:
  rG LLVM Github Monorepo

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

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/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,109 @@
+//===- 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>(),
+                             R"(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>(),
+                             R"(@interface O
+                                + alloc;
+                                - initWithInt:(int)q;
+                                @end
+
+                                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
@@ -7,6 +7,7 @@
   AnalyzerOptionsTest.cpp
   CallDescriptionTest.cpp
   CallEventTest.cpp
+  ParamRegionTest.cpp
   RangeSetTest.cpp
   RegisterCustomCheckersTest.cpp
   StoreTest.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,11 +160,9 @@
 }
 
 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);
-}
+const ObjCIvarDecl *ObjCIvarRegion::getDecl() const { return IVD; }
 
 QualType ObjCIvarRegion::getValueType() const {
   return getDecl()->getType();
@@ -178,6 +176,33 @@
   return QualType(getDecl()->getTypeForDecl(), 0);
 }
 
+QualType ParamVarRegion::getValueType() const {
+  assert(getDecl() &&
+         "`ParamVarRegion` support functions without `Decl` not implemented"
+         " yet.");
+  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 +274,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 ObjCIvarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, getDecl(), 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 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 VarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
-  VarRegion::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 ParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, getOriginExpr(), getIndex(), superRegion);
 }
 
 void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym,
@@ -479,12 +523,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 +574,18 @@
   os << "StackLocalsSpaceRegion";
 }
 
+void ParamVarRegion::dumpToStream(raw_ostream &os) const {
+  const ParmVarDecl *PVD = getDecl();
+  assert(PVD &&
+         "`ParamVarRegion` support functions without `Decl` not implemented"
+         " yet.");
+  if (const IdentifierInfo *ID = PVD->getIdentifier()) {
+    os << ID->getName();
+  } else {
+    os << "ParamVarRegion{P" << PVD->getID() << '}';
+  }
+}
+
 bool MemRegion::canPrintPretty() const {
   return canPrintPrettyAsExpr();
 }
@@ -550,11 +605,18 @@
   llvm_unreachable("This region cannot be printed pretty.");
 }
 
-bool VarRegion::canPrintPrettyAsExpr() const {
-  return true;
+bool NonParamVarRegion::canPrintPrettyAsExpr() const { return true; }
+
+void NonParamVarRegion::printPrettyAsExpr(raw_ostream &os) const {
+  os << getDecl()->getName();
 }
 
-void VarRegion::printPrettyAsExpr(raw_ostream &os) const {
+bool ParamVarRegion::canPrintPrettyAsExpr() const { return true; }
+
+void ParamVarRegion::printPrettyAsExpr(raw_ostream &os) const {
+  assert(getDecl() &&
+         "`ParamVarRegion` support functions without `Decl` not implemented"
+         " yet.");
   os << getDecl()->getName();
 }
 
@@ -693,7 +755,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 +910,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 +923,30 @@
   return (const StackFrameContext *)nullptr;
 }
 
-const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
+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 +1029,23 @@
     }
   }
 
-  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 +1438,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 +1595,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 +1604,7 @@
       OriginalVR = VR;
     }
     else {
-      VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion());
+      VR = MemMgr.getNonParamVarRegion(VD, MemMgr.getUnknownRegion());
       OriginalVR = MemMgr.getVarRegion(VD, LC);
     }
   }
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -303,12 +303,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,17 @@
   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 +303,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 +506,8 @@
     // 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,12 @@
 
 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 +906,9 @@
 class VarRegion : public DeclRegion {
   friend class MemRegionManager;
 
-  // Constructors and private methods.
-  VarRegion(const VarDecl *vd, const MemRegion *sReg)
-      : DeclRegion(vd, sReg, VarRegionKind) {
+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,
@@ -925,17 +917,45 @@
            isa<BlockDataRegion>(sReg) || isa<UnknownSpaceRegion>(sReg));
   }
 
-  static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD,
-                            const MemRegion *superRegion) {
-    DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
+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();
   }
 
-public:
-  void Profile(llvm::FoldingSetNodeID& ID) const override;
+  static bool classof(const MemRegion *R) {
+    unsigned k = R->getKind();
+    return k >= BEGIN_VAR_REGIONS && k <= END_VAR_REGIONS;
+  }
+};
 
-  const VarDecl *getDecl() const { return cast<VarDecl>(D); }
+class NonParamVarRegion : public VarRegion {
+  friend class MemRegionManager;
 
-  const StackFrameContext *getStackFrame() const;
+  const VarDecl *VD;
+
+  // Constructors and private methods.
+  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,
+    // which, unlike everything else on this list, are not memory spaces.
+    assert(isa<GlobalsSpaceRegion>(sReg) || isa<StackSpaceRegion>(sReg) ||
+           isa<BlockDataRegion>(sReg) || isa<UnknownSpaceRegion>(sReg));
+  }
+
+  static void ProfileRegion(llvm::FoldingSetNodeID &ID, const VarDecl *VD,
+                            const MemRegion *superRegion);
+
+public:
+  void Profile(llvm::FoldingSetNodeID &ID) const override;
+
+  const VarDecl *getDecl() const override { return VD; }
 
   QualType getValueType() const override {
     // FIXME: We can cache this if needed.
@@ -949,7 +969,50 @@
   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 unknown 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 +1054,22 @@
 class FieldRegion : public DeclRegion {
   friend class MemRegionManager;
 
-  FieldRegion(const FieldDecl *fd, const SubRegion* sReg)
-      : DeclRegion(fd, sReg, FieldRegionKind) {}
+  const FieldDecl *FD;
 
-  static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD,
+  FieldRegion(const FieldDecl *fd, const SubRegion *sReg)
+      : 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 +1091,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 +1100,9 @@
 
 public:
   const ObjCIvarDecl *getDecl() const;
+
+  void Profile(llvm::FoldingSetNodeID& ID) const override;
+
   QualType getValueType() const override;
 
   bool canPrintPrettyAsExpr() const override;
@@ -1312,11 +1386,18 @@
 
   /// 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
@@ -402,9 +402,10 @@
   const StackFrameContext *getCalleeStackFrame(unsigned BlockCount) const;
 
   /// 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;
+  /// frame. The behavior is undefined if the block count is different from the
+  /// one that is there when call happens. May fail; returns null on failure.
+  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
@@ -18,6 +18,7 @@
 #include "clang/AST/Attr.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
+#include "llvm/ADT/StringExtras.h"
 
 namespace clang {
 
@@ -179,7 +180,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 +217,39 @@
            "' 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 << llvm::getOrdinalSuffix(Index) << " parameter 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