summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorDevin Coughlin <dcoughlin@apple.com>2016-12-22 17:52:57 +0000
committerDevin Coughlin <dcoughlin@apple.com>2016-12-22 17:52:57 +0000
commite17f6215292a87ac449eae820cb7557f0812f57b (patch)
tree378999997f35ffdb39cb89b94504b51082fd9eaf /clang/lib
parent941632839f6f4f122c2f1dd1de369bb304aa6ada (diff)
downloadbcm5719-llvm-e17f6215292a87ac449eae820cb7557f0812f57b.tar.gz
bcm5719-llvm-e17f6215292a87ac449eae820cb7557f0812f57b.zip
[analyzer] Update GTestChecker to tighten API detection
Update the GTestChecker to tighten up the API detection and make it cleaner in response to post-commit feedback. Also add tests for when temporary destructors are enabled to make sure we get the expected behavior when inlining constructors for temporaries. llvm-svn: 290352
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp84
1 files changed, 48 insertions, 36 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp
index eb7c2874b94..f0be41b293e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This checker models the behavior of un-inlined APIs from the the gtest
+// This checker models the behavior of un-inlined APIs from the gtest
// unit-testing library to avoid false positives when using assertions from
// that library.
//
@@ -85,7 +85,7 @@ using namespace ento;
// does not inline these since it does not yet reliably call temporary
// destructors).
//
-// This checker compensates for the missing inlining by propgagating the
+// This checker compensates for the missing inlining by propagating the
// _success value across the bool and copy constructors so the assertion behaves
// as expected.
@@ -102,7 +102,7 @@ public:
private:
void modelAssertionResultBoolConstructor(const CXXConstructorCall *Call,
- CheckerContext &C) const;
+ bool IsRef, CheckerContext &C) const;
void modelAssertionResultCopyConstructor(const CXXConstructorCall *Call,
CheckerContext &C) const;
@@ -122,35 +122,25 @@ private:
GTestChecker::GTestChecker() : AssertionResultII(nullptr), SuccessII(nullptr) {}
-/// Model a call to an un-inlined AssertionResult(boolean expression).
+/// Model a call to an un-inlined AssertionResult(bool) or
+/// AssertionResult(bool &, ...).
/// To do so, constrain the value of the newly-constructed instance's 'success_'
/// field to be equal to the passed-in boolean value.
+///
+/// \param IsRef Whether the boolean parameter is a reference or not.
void GTestChecker::modelAssertionResultBoolConstructor(
- const CXXConstructorCall *Call, CheckerContext &C) const {
- assert(Call->getNumArgs() > 0);
-
- // Depending on the version of gtest the constructor can be either of:
- //
- // v1.7 and earlier:
- // AssertionResult(bool success)
- //
- // v1.8 and greater:
- // template <typename T>
- // AssertionResult(const T& success,
- // typename internal::EnableIf<
- // !internal::ImplicitlyConvertible<T,
- // AssertionResult>::value>::type*)
+ const CXXConstructorCall *Call, bool IsRef, CheckerContext &C) const {
+ assert(Call->getNumArgs() >= 1 && Call->getNumArgs() <= 2);
+ ProgramStateRef State = C.getState();
SVal BooleanArgVal = Call->getArgSVal(0);
- if (Call->getDecl()->getParamDecl(0)->getType()->getAs<ReferenceType>()) {
- // We have v1.8+, so load the value from the reference.
+ if (IsRef) {
+ // The argument is a reference, so load from it to get the boolean value.
if (!BooleanArgVal.getAs<Loc>())
return;
BooleanArgVal = C.getState()->getSVal(BooleanArgVal.castAs<Loc>());
}
- ProgramStateRef State = C.getState();
-
SVal ThisVal = Call->getCXXThisVal();
SVal ThisSuccess = getAssertionResultSuccessFieldValue(
@@ -169,7 +159,7 @@ void GTestChecker::modelAssertionResultBoolConstructor(
/// 'success_' field.
void GTestChecker::modelAssertionResultCopyConstructor(
const CXXConstructorCall *Call, CheckerContext &C) const {
- assert(Call->getNumArgs() > 0);
+ assert(Call->getNumArgs() == 1);
// The first parameter of the the copy constructor must be the other
// instance to initialize this instances fields from.
@@ -206,22 +196,44 @@ void GTestChecker::checkPostCall(const CallEvent &Call,
if (CtorParent->getIdentifier() != AssertionResultII)
return;
- if (CtorDecl->getNumParams() == 0)
- return;
-
+ unsigned ParamCount = CtorDecl->getNumParams();
- // Call the appropriate modeling method based on the type of the first
- // constructor parameter.
- const ParmVarDecl *ParamDecl = CtorDecl->getParamDecl(0);
- QualType ParamType = ParamDecl->getType();
- if (CtorDecl->getNumParams() <= 2 &&
- ParamType.getNonReferenceType()->getCanonicalTypeUnqualified() ==
- C.getASTContext().BoolTy) {
- // The first parameter is either a boolean or reference to a boolean
- modelAssertionResultBoolConstructor(CtorCall, C);
+ // Call the appropriate modeling method based the parameters and their
+ // types.
- } else if (CtorDecl->isCopyConstructor()) {
+ // We have AssertionResult(const &AssertionResult)
+ if (CtorDecl->isCopyConstructor() && ParamCount == 1) {
modelAssertionResultCopyConstructor(CtorCall, C);
+ return;
+ }
+
+ // There are two possible boolean constructors, depending on which
+ // version of gtest is being used:
+ //
+ // v1.7 and earlier:
+ // AssertionResult(bool success)
+ //
+ // v1.8 and greater:
+ // template <typename T>
+ // AssertionResult(const T& success,
+ // typename internal::EnableIf<
+ // !internal::ImplicitlyConvertible<T,
+ // AssertionResult>::value>::type*)
+ //
+ CanQualType BoolTy = C.getASTContext().BoolTy;
+ if (ParamCount == 1 && CtorDecl->getParamDecl(0)->getType() == BoolTy) {
+ // We have AssertionResult(bool)
+ modelAssertionResultBoolConstructor(CtorCall, /*IsRef=*/false, C);
+ return;
+ }
+ if (ParamCount == 2){
+ auto *RefTy = CtorDecl->getParamDecl(0)->getType()->getAs<ReferenceType>();
+ if (RefTy &&
+ RefTy->getPointeeType()->getCanonicalTypeUnqualified() == BoolTy) {
+ // We have AssertionResult(bool &, ...)
+ modelAssertionResultBoolConstructor(CtorCall, /*IsRef=*/true, C);
+ return;
+ }
}
}
OpenPOWER on IntegriCloud