summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2018-06-25 23:43:45 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2018-06-25 23:43:45 +0000
commitf74ef4b1e634f094654de3b7b3567fa747c7e8a8 (patch)
tree9f0e183dfd3aa861f944b27870dea6734ca7bcac
parenta157b8bef546f96d2c1940a9a27626c9f0da5074 (diff)
downloadbcm5719-llvm-f74ef4b1e634f094654de3b7b3567fa747c7e8a8.tar.gz
bcm5719-llvm-f74ef4b1e634f094654de3b7b3567fa747c7e8a8.zip
[analyzer] Fix invalidation on C++ const methods with arrow syntax.
Conservative evaluation of a C++ method call would invalidate the object, as long as the method is not const or the object has mutable fields. When checking for mutable fields, we need to scan the type of the object on which the method is called, which may be more specific than the type of the object on which the method is defined, hence we look up the type from the this-argument expression. If arrow syntax or implicit-this syntax is used, this-argument expression has pointer type, not record type, and lookup accidentally failed for that reason. Obtain object type correctly. Differential Revision: https://reviews.llvm.org/D48460 llvm-svn: 335555
-rw-r--r--clang/lib/StaticAnalyzer/Core/CallEvent.cpp9
-rw-r--r--clang/test/Analysis/const-method-call.cpp24
2 files changed, 31 insertions, 2 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index a7d0f3894b7..2b2de16dbdf 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -534,9 +534,14 @@ void CXXInstanceCall::getExtraInvalidatedValues(
// Get the record decl for the class of 'This'. D->getParent() may return a
// base class decl, rather than the class of the instance which needs to be
// checked for mutable fields.
+ // TODO: We might as well look at the dynamic type of the object.
const Expr *Ex = getCXXThisExpr()->ignoreParenBaseCasts();
- const CXXRecordDecl *ParentRecord = Ex->getType()->getAsCXXRecordDecl();
- if (!ParentRecord || ParentRecord->hasMutableFields())
+ QualType T = Ex->getType();
+ if (T->isPointerType()) // Arrow or implicit-this syntax?
+ T = T->getPointeeType();
+ const CXXRecordDecl *ParentRecord = T->getAsCXXRecordDecl();
+ assert(ParentRecord);
+ if (ParentRecord->hasMutableFields())
return;
// Preserve CXXThis.
const MemRegion *ThisRegion = ThisVal.getAsRegion();
diff --git a/clang/test/Analysis/const-method-call.cpp b/clang/test/Analysis/const-method-call.cpp
index 17df2a016b8..a5a38929c22 100644
--- a/clang/test/Analysis/const-method-call.cpp
+++ b/clang/test/Analysis/const-method-call.cpp
@@ -6,6 +6,14 @@ struct A {
int x;
void foo() const;
void bar();
+
+ void testImplicitThisSyntax() {
+ x = 3;
+ foo();
+ clang_analyzer_eval(x == 3); // expected-warning{{TRUE}}
+ bar();
+ clang_analyzer_eval(x == 3); // expected-warning{{UNKNOWN}}
+ }
};
struct B {
@@ -108,6 +116,22 @@ void checkThatContainedConstMethodDoesNotInvalidateObjects() {
clang_analyzer_eval(t.in.x == 2); // expected-warning{{TRUE}}
}
+void checkPointerTypedThisExpression(A *a) {
+ a->x = 3;
+ a->foo();
+ clang_analyzer_eval(a->x == 3); // expected-warning{{TRUE}}
+ a->bar();
+ clang_analyzer_eval(a->x == 3); // expected-warning{{UNKNOWN}}
+}
+
+void checkReferenceTypedThisExpression(A &a) {
+ a.x = 3;
+ a.foo();
+ clang_analyzer_eval(a.x == 3); // expected-warning{{TRUE}}
+ a.bar();
+ clang_analyzer_eval(a.x == 3); // expected-warning{{UNKNOWN}}
+}
+
// --- Versions of the above tests where the const method is inherited --- //
struct B1 {
OpenPOWER on IntegriCloud