1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
16 | #include "clang/AST/Expr.h" |
17 | #include "clang/Basic/LangOptions.h" |
18 | #include "clang/StaticAnalyzer/Core/Checker.h" |
19 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" |
20 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
21 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" |
22 | #include "llvm/Support/raw_ostream.h" |
23 | |
24 | using namespace clang; |
25 | using namespace ento; |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | |
73 | |
74 | |
75 | |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | |
91 | namespace { |
92 | class GTestChecker : public Checker<check::PostCall> { |
93 | |
94 | mutable IdentifierInfo *AssertionResultII; |
95 | mutable IdentifierInfo *SuccessII; |
96 | |
97 | public: |
98 | GTestChecker(); |
99 | |
100 | void checkPostCall(const CallEvent &Call, CheckerContext &C) const; |
101 | |
102 | private: |
103 | void modelAssertionResultBoolConstructor(const CXXConstructorCall *Call, |
104 | bool IsRef, CheckerContext &C) const; |
105 | |
106 | void modelAssertionResultCopyConstructor(const CXXConstructorCall *Call, |
107 | CheckerContext &C) const; |
108 | |
109 | void initIdentifierInfo(ASTContext &Ctx) const; |
110 | |
111 | SVal |
112 | getAssertionResultSuccessFieldValue(const CXXRecordDecl *AssertionResultDecl, |
113 | SVal Instance, |
114 | ProgramStateRef State) const; |
115 | |
116 | static ProgramStateRef assumeValuesEqual(SVal Val1, SVal Val2, |
117 | ProgramStateRef State, |
118 | CheckerContext &C); |
119 | }; |
120 | } |
121 | |
122 | GTestChecker::GTestChecker() : AssertionResultII(nullptr), SuccessII(nullptr) {} |
123 | |
124 | |
125 | |
126 | |
127 | |
128 | |
129 | |
130 | void GTestChecker::modelAssertionResultBoolConstructor( |
131 | const CXXConstructorCall *Call, bool IsRef, CheckerContext &C) const { |
132 | getNumArgs() >= 1 && Call->getNumArgs() <= 2", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp", 132, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Call->getNumArgs() >= 1 && Call->getNumArgs() <= 2); |
133 | |
134 | ProgramStateRef State = C.getState(); |
135 | SVal BooleanArgVal = Call->getArgSVal(0); |
136 | if (IsRef) { |
137 | |
138 | if (!BooleanArgVal.getAs<Loc>()) |
139 | return; |
140 | BooleanArgVal = C.getState()->getSVal(BooleanArgVal.castAs<Loc>()); |
141 | } |
142 | |
143 | SVal ThisVal = Call->getCXXThisVal(); |
144 | |
145 | SVal ThisSuccess = getAssertionResultSuccessFieldValue( |
146 | Call->getDecl()->getParent(), ThisVal, State); |
147 | |
148 | State = assumeValuesEqual(ThisSuccess, BooleanArgVal, State, C); |
149 | C.addTransition(State); |
150 | } |
151 | |
152 | |
153 | |
154 | |
155 | |
156 | |
157 | |
158 | |
159 | void GTestChecker::modelAssertionResultCopyConstructor( |
160 | const CXXConstructorCall *Call, CheckerContext &C) const { |
161 | getNumArgs() == 1", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp", 161, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Call->getNumArgs() == 1); |
162 | |
163 | |
164 | |
165 | SVal OtherVal = Call->getArgSVal(0); |
166 | SVal ThisVal = Call->getCXXThisVal(); |
167 | |
168 | const CXXRecordDecl *AssertResultClassDecl = Call->getDecl()->getParent(); |
169 | ProgramStateRef State = C.getState(); |
170 | |
171 | SVal ThisSuccess = getAssertionResultSuccessFieldValue(AssertResultClassDecl, |
172 | ThisVal, State); |
173 | SVal OtherSuccess = getAssertionResultSuccessFieldValue(AssertResultClassDecl, |
174 | OtherVal, State); |
175 | |
176 | State = assumeValuesEqual(ThisSuccess, OtherSuccess, State, C); |
177 | C.addTransition(State); |
178 | } |
179 | |
180 | |
181 | void GTestChecker::checkPostCall(const CallEvent &Call, |
182 | CheckerContext &C) const { |
183 | |
184 | if (C.wasInlined) |
185 | return; |
186 | |
187 | initIdentifierInfo(C.getASTContext()); |
188 | |
189 | auto *CtorCall = dyn_cast<CXXConstructorCall>(&Call); |
190 | if (!CtorCall) |
191 | return; |
192 | |
193 | const CXXConstructorDecl *CtorDecl = CtorCall->getDecl(); |
194 | const CXXRecordDecl *CtorParent = CtorDecl->getParent(); |
195 | if (CtorParent->getIdentifier() != AssertionResultII) |
196 | return; |
197 | |
198 | unsigned ParamCount = CtorDecl->getNumParams(); |
199 | |
200 | |
201 | |
202 | |
203 | |
204 | if (CtorDecl->isCopyConstructor() && ParamCount == 1) { |
205 | modelAssertionResultCopyConstructor(CtorCall, C); |
206 | return; |
207 | } |
208 | |
209 | |
210 | |
211 | |
212 | |
213 | |
214 | |
215 | |
216 | |
217 | |
218 | |
219 | |
220 | |
221 | |
222 | CanQualType BoolTy = C.getASTContext().BoolTy; |
223 | if (ParamCount == 1 && CtorDecl->getParamDecl(0)->getType() == BoolTy) { |
224 | |
225 | modelAssertionResultBoolConstructor(CtorCall, , C); |
226 | return; |
227 | } |
228 | if (ParamCount == 2){ |
229 | auto *RefTy = CtorDecl->getParamDecl(0)->getType()->getAs<ReferenceType>(); |
230 | if (RefTy && |
231 | RefTy->getPointeeType()->getCanonicalTypeUnqualified() == BoolTy) { |
232 | |
233 | modelAssertionResultBoolConstructor(CtorCall, , C); |
234 | return; |
235 | } |
236 | } |
237 | } |
238 | |
239 | void GTestChecker::initIdentifierInfo(ASTContext &Ctx) const { |
240 | if (AssertionResultII) |
241 | return; |
242 | |
243 | AssertionResultII = &Ctx.Idents.get("AssertionResult"); |
244 | SuccessII = &Ctx.Idents.get("success_"); |
245 | } |
246 | |
247 | |
248 | |
249 | SVal GTestChecker::getAssertionResultSuccessFieldValue( |
250 | const CXXRecordDecl *AssertionResultDecl, SVal Instance, |
251 | ProgramStateRef State) const { |
252 | |
253 | DeclContext::lookup_result Result = AssertionResultDecl->lookup(SuccessII); |
254 | if (Result.empty()) |
255 | return UnknownVal(); |
256 | |
257 | auto *SuccessField = dyn_cast<FieldDecl>(Result.front()); |
258 | if (!SuccessField) |
259 | return UnknownVal(); |
260 | |
261 | Optional<Loc> FieldLoc = |
262 | State->getLValue(SuccessField, Instance).getAs<Loc>(); |
263 | if (!FieldLoc.hasValue()) |
264 | return UnknownVal(); |
265 | |
266 | return State->getSVal(*FieldLoc); |
267 | } |
268 | |
269 | |
270 | ProgramStateRef GTestChecker::assumeValuesEqual(SVal Val1, SVal Val2, |
271 | ProgramStateRef State, |
272 | CheckerContext &C) { |
273 | if (!Val1.getAs<DefinedOrUnknownSVal>() || |
274 | !Val2.getAs<DefinedOrUnknownSVal>()) |
275 | return State; |
276 | |
277 | auto ValuesEqual = |
278 | C.getSValBuilder().evalEQ(State, Val1.castAs<DefinedOrUnknownSVal>(), |
279 | Val2.castAs<DefinedOrUnknownSVal>()); |
280 | |
281 | if (!ValuesEqual.getAs<DefinedSVal>()) |
282 | return State; |
283 | |
284 | State = C.getConstraintManager().assume( |
285 | State, ValuesEqual.castAs<DefinedSVal>(), true); |
286 | |
287 | return State; |
288 | } |
289 | |
290 | void ento::registerGTestChecker(CheckerManager &Mgr) { |
291 | Mgr.registerChecker<GTestChecker>(); |
292 | } |
293 | |
294 | bool ento::shouldRegisterGTestChecker(const LangOptions &LO) { |
295 | |
296 | |
297 | return LO.CPlusPlus; |
298 | } |
299 | |