seaneveson updated this revision to Diff 35617.
seaneveson added a comment.

Removed unnecessary call to getCanonical.
Changed if statement checking getting ThisRegion to an assert.
Added code to handle mutable members of base classes.


http://reviews.llvm.org/D13099

Files:
  lib/StaticAnalyzer/Core/CallEvent.cpp
  test/Analysis/PR21606.cpp
  test/Analysis/method-call.cpp

Index: test/Analysis/method-call.cpp
===================================================================
--- test/Analysis/method-call.cpp
+++ test/Analysis/method-call.cpp
@@ -13,6 +13,25 @@
   int x;
 };
 
+struct C {
+  int x;
+  void foo() const;
+  void bar();
+};
+
+struct D {
+  mutable int x;
+  void foo() const;
+};
+
+struct Base {
+  mutable int x;
+};
+
+struct Derived : Base {
+  void foo() const;
+};
+
 void testNullObject(A *a) {
   clang_analyzer_eval(a); // expected-warning{{UNKNOWN}}
   (void)a->getx(); // assume we know what we're doing
@@ -45,3 +64,27 @@
   B t2(t);
   clang_analyzer_eval(t.x == 0); // expected-warning{{TRUE}}
 }
+
+void checkThatConstMethodWithoutDefinitionDoesNotInvalidateObject() {
+  C t;
+  t.x = 3;
+  t.foo();
+  clang_analyzer_eval(t.x == 3); // expected-warning{{TRUE}}
+  // Test non-const does invalidate
+  t.bar();
+  clang_analyzer_eval(t.x); // expected-warning{{UNKNOWN}}
+}
+
+void checkThatConstMethodDoesInvalidateMutableFields() {
+  D t;
+  t.x = 3;
+  t.foo();
+  clang_analyzer_eval(t.x); // expected-warning{{UNKNOWN}}
+}
+
+void checkThatConstMethodDoesInvalidateInheritedMutableFields() {
+  Derived t;
+  t.x = 3;
+  t.foo();
+  clang_analyzer_eval(t.x); // expected-warning{{UNKNOWN}}
+}
Index: test/Analysis/PR21606.cpp
===================================================================
--- test/Analysis/PR21606.cpp
+++ test/Analysis/PR21606.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core
+// PR21606
+
+struct s1 {
+    void g(const int *i) const;
+};
+
+struct s2 {
+    void f(int *i) {
+        m_i = i;
+        m_s.g(m_i);
+        if (m_i)
+            *i = 42; // no-warning
+    }
+
+    int *m_i;
+    s1 m_s;
+};
+
+int main()
+{
+    s2().f(0);
+}
Index: lib/StaticAnalyzer/Core/CallEvent.cpp
===================================================================
--- lib/StaticAnalyzer/Core/CallEvent.cpp
+++ lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -403,7 +403,40 @@
   return getSVal(CE->getCallee()).getAsFunctionDecl();
 }
 
+/// Get all mutable fields of Record and its base classes.
+static void getMutableFields(const CXXRecordDecl *Record,
+                             SmallVector<const FieldDecl *, 8> &MutFields) {
+  if (Record == nullptr)
+    return;
+  for (auto F : Record->fields()) {
+    if (F->isMutable())
+      MutFields.push_back(F);
+  }
+  for (auto C : Record->bases()) {
+    getMutableFields(C.getType()->getAsCXXRecordDecl(), MutFields);
+  }
+}
+
 void CXXInstanceCall::getExtraInvalidatedValues(ValueList &Values) const {
+  // Check if this is a call to a const method.
+  if (const CXXMethodDecl *D = cast_or_null<CXXMethodDecl>(getDecl())) {
+    if(D->isConst()) {
+      // Get any mutable members and invalidate them.
+      SmallVector<const FieldDecl *, 8> MutableFields;
+      getMutableFields(D->getParent(), MutableFields);
+      if (!MutableFields.empty()) {
+        const MemRegion *ThisRegion = getCXXThisVal().getAsRegion();
+        assert(ThisRegion && "CXXThisVal was not a region");
+        MemRegionManager *MemMgr = ThisRegion->getMemRegionManager();
+        for (auto it = MutableFields.begin(), end = MutableFields.end();
+             it != end; ++it) {
+          const FieldRegion *FR = MemMgr->getFieldRegion(*it, ThisRegion);
+          Values.push_back(loc::MemRegionVal(FR));
+        }
+      }
+      return;
+    }
+  }
   Values.push_back(getCXXThisVal());
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to