Improve flat store: MemRegion::getAsOffset() computes a region's offset within
the top-level object. FlatStore now can bind and retrieve element and field
regions.
PR7297 is fixed by flat store.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110020 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp
index 9cfeb7a..d9c559e 100644
--- a/lib/Checker/MemRegion.cpp
+++ b/lib/Checker/MemRegion.cpp
@@ -18,6 +18,7 @@
 #include "clang/Analysis/AnalysisContext.h"
 #include "clang/Analysis/Support/BumpVector.h"
 #include "clang/AST/CharUnits.h"
+#include "clang/AST/RecordLayout.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace clang;
@@ -785,7 +786,7 @@
   return true;
 }
 
-RegionRawOffset ElementRegion::getAsRawOffset() const {
+RegionRawOffset ElementRegion::getAsArrayOffset() const {
   CharUnits offset = CharUnits::Zero();
   const ElementRegion *ER = this;
   const MemRegion *superR = NULL;
@@ -827,6 +828,50 @@
   return RegionRawOffset(superR, offset.getQuantity());
 }
 
+RegionOffset ElementRegion::getAsOffset() const {
+  uint64_t Offset;
+  if (const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Index)) {
+    int64_t i = CI->getValue().getSExtValue();
+    assert(i >= 0);
+    // We cannot compute offset for incomplete types.
+    if (!IsCompleteType(getContext(), ElementType))
+      return RegionOffset(0); 
+    
+    CharUnits Size = getContext().getTypeSizeInChars(ElementType);
+    Offset = i * Size.getQuantity() * 8;
+  } else
+    // We cannot compute offset for symbolic index.
+    return RegionOffset(0);
+
+  // Get the offset of the super region.
+  RegionOffset SOffset = cast<SubRegion>(superRegion)->getAsOffset();
+  if (!SOffset.getRegion())
+    return RegionOffset(0);
+  else
+    return RegionOffset(SOffset.getRegion(), SOffset.getOffset() + Offset);
+}
+
+RegionOffset FieldRegion::getAsOffset() const {
+  const RecordDecl *RD = getDecl()->getParent();
+  assert(RD->isDefinition());
+  // Get the field number.
+  unsigned idx = 0;
+  for (RecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end();
+       FI != FE; ++FI, ++idx)
+    if (getDecl() == *FI)
+      break;
+
+  const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+  // This is offset in bits.
+  uint64_t Offset = Layout.getFieldOffset(idx);
+
+  RegionOffset SOffset = cast<SubRegion>(superRegion)->getAsOffset();
+  if (!SOffset.getRegion())
+    return RegionOffset(0);
+  else
+    return RegionOffset(SOffset.getRegion(), SOffset.getOffset() + Offset);
+}
+
 //===----------------------------------------------------------------------===//
 // BlockDataRegion
 //===----------------------------------------------------------------------===//