22 #include "llvm/Support/raw_ostream.h"
24 using namespace clang;
92 class GTestChecker :
public Checker<check::PostCall> {
100 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const;
103 void modelAssertionResultBoolConstructor(
const CXXConstructorCall *Call,
104 bool IsRef, CheckerContext &C)
const;
106 void modelAssertionResultCopyConstructor(
const CXXConstructorCall *Call,
107 CheckerContext &C)
const;
109 void initIdentifierInfo(
ASTContext &Ctx)
const;
112 getAssertionResultSuccessFieldValue(
const CXXRecordDecl *AssertionResultDecl,
122 GTestChecker::GTestChecker() : AssertionResultII(nullptr), SuccessII(nullptr) {}
130 void GTestChecker::modelAssertionResultBoolConstructor(
131 const CXXConstructorCall *Call,
bool IsRef, CheckerContext &
C)
const {
132 assert(
Call->getNumArgs() >= 1 &&
Call->getNumArgs() <= 2);
135 SVal BooleanArgVal =
Call->getArgSVal(0);
138 if (!isa<Loc>(BooleanArgVal))
140 BooleanArgVal =
C.getState()->getSVal(BooleanArgVal.castAs<Loc>());
143 SVal ThisVal =
Call->getCXXThisVal();
145 SVal ThisSuccess = getAssertionResultSuccessFieldValue(
146 Call->getDecl()->getParent(), ThisVal,
State);
148 State = assumeValuesEqual(ThisSuccess, BooleanArgVal,
State,
C);
159 void GTestChecker::modelAssertionResultCopyConstructor(
160 const CXXConstructorCall *Call, CheckerContext &
C)
const {
161 assert(
Call->getNumArgs() == 1);
165 SVal OtherVal =
Call->getArgSVal(0);
166 SVal ThisVal =
Call->getCXXThisVal();
171 SVal ThisSuccess = getAssertionResultSuccessFieldValue(AssertResultClassDecl,
173 SVal OtherSuccess = getAssertionResultSuccessFieldValue(AssertResultClassDecl,
176 State = assumeValuesEqual(ThisSuccess, OtherSuccess,
State,
C);
181 void GTestChecker::checkPostCall(
const CallEvent &Call,
182 CheckerContext &
C)
const {
187 initIdentifierInfo(
C.getASTContext());
189 auto *CtorCall = dyn_cast<CXXConstructorCall>(&Call);
205 modelAssertionResultCopyConstructor(CtorCall,
C);
225 modelAssertionResultBoolConstructor(CtorCall,
false,
C);
228 if (ParamCount == 2){
231 RefTy->getPointeeType()->getCanonicalTypeUnqualified() == BoolTy) {
233 modelAssertionResultBoolConstructor(CtorCall,
true,
C);
239 void GTestChecker::initIdentifierInfo(
ASTContext &Ctx)
const {
240 if (AssertionResultII)
243 AssertionResultII = &Ctx.
Idents.
get(
"AssertionResult");
249 SVal GTestChecker::getAssertionResultSuccessFieldValue(
257 auto *SuccessField = dyn_cast<FieldDecl>(Result.front());
262 State->getLValue(SuccessField, Instance).getAs<Loc>();
266 return State->getSVal(*FieldLoc);
273 auto DVal1 = Val1.getAs<DefinedOrUnknownSVal>();
274 auto DVal2 = Val2.getAs<DefinedOrUnknownSVal>();
275 if (!DVal1 || !DVal2)
279 C.getSValBuilder().evalEQ(
State, *DVal1, *DVal2).getAs<DefinedSVal>();
283 State =
C.getConstraintManager().assume(
State, *ValuesEqual,
true);
287 void ento::registerGTestChecker(CheckerManager &Mgr) {
288 Mgr.registerChecker<GTestChecker>();
291 bool ento::shouldRegisterGTestChecker(
const CheckerManager &mgr) {