1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | #include "clang/Analysis/BodyFarm.h" |
15 | #include "clang/AST/ASTContext.h" |
16 | #include "clang/AST/CXXInheritance.h" |
17 | #include "clang/AST/Decl.h" |
18 | #include "clang/AST/Expr.h" |
19 | #include "clang/AST/ExprCXX.h" |
20 | #include "clang/AST/ExprObjC.h" |
21 | #include "clang/AST/NestedNameSpecifier.h" |
22 | #include "clang/Analysis/CodeInjector.h" |
23 | #include "clang/Basic/OperatorKinds.h" |
24 | #include "llvm/ADT/StringSwitch.h" |
25 | #include "llvm/Support/Debug.h" |
26 | |
27 | #define DEBUG_TYPE "body-farm" |
28 | |
29 | using namespace clang; |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | static bool isDispatchBlock(QualType Ty) { |
36 | |
37 | const BlockPointerType *BPT = Ty->getAs<BlockPointerType>(); |
38 | if (!BPT) |
39 | return false; |
40 | |
41 | |
42 | |
43 | const FunctionProtoType *FT = |
44 | BPT->getPointeeType()->getAs<FunctionProtoType>(); |
45 | return FT && FT->getReturnType()->isVoidType() && FT->getNumParams() == 0; |
46 | } |
47 | |
48 | namespace { |
49 | class ASTMaker { |
50 | public: |
51 | ASTMaker(ASTContext &C) : C(C) {} |
52 | |
53 | |
54 | BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty); |
55 | |
56 | |
57 | BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS, |
58 | BinaryOperator::Opcode Op); |
59 | |
60 | |
61 | CompoundStmt *makeCompound(ArrayRef<Stmt*>); |
62 | |
63 | |
64 | DeclRefExpr *makeDeclRefExpr(const VarDecl *D, |
65 | bool RefersToEnclosingVariableOrCapture = false); |
66 | |
67 | |
68 | UnaryOperator *makeDereference(const Expr *Arg, QualType Ty); |
69 | |
70 | |
71 | Expr *makeIntegralCast(const Expr *Arg, QualType Ty); |
72 | |
73 | |
74 | ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg); |
75 | |
76 | |
77 | ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty); |
78 | |
79 | |
80 | |
81 | ImplicitCastExpr * |
82 | makeLvalueToRvalue(const VarDecl *Decl, |
83 | bool RefersToEnclosingVariableOrCapture = false); |
84 | |
85 | |
86 | ImplicitCastExpr *makeImplicitCast(const Expr *Arg, QualType Ty, |
87 | CastKind CK = CK_LValueToRValue); |
88 | |
89 | |
90 | ObjCBoolLiteralExpr *makeObjCBool(bool Val); |
91 | |
92 | |
93 | ObjCIvarRefExpr *makeObjCIvarRef(const Expr *Base, const ObjCIvarDecl *IVar); |
94 | |
95 | |
96 | ReturnStmt *makeReturn(const Expr *RetVal); |
97 | |
98 | |
99 | IntegerLiteral *makeIntegerLiteral(uint64_t Value, QualType Ty); |
100 | |
101 | |
102 | MemberExpr *makeMemberExpression(Expr *base, ValueDecl *MemberDecl, |
103 | bool IsArrow = false, |
104 | ExprValueKind ValueKind = VK_LValue); |
105 | |
106 | |
107 | |
108 | ValueDecl *findMemberField(const RecordDecl *RD, StringRef Name); |
109 | |
110 | private: |
111 | ASTContext &C; |
112 | }; |
113 | } |
114 | |
115 | BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS, |
116 | QualType Ty) { |
117 | return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS), |
118 | BO_Assign, Ty, VK_RValue, |
119 | OK_Ordinary, SourceLocation(), FPOptions()); |
120 | } |
121 | |
122 | BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS, |
123 | BinaryOperator::Opcode Op) { |
124 | assert(BinaryOperator::isLogicalOp(Op) || |
125 | BinaryOperator::isComparisonOp(Op)); |
126 | return new (C) BinaryOperator(const_cast<Expr*>(LHS), |
127 | const_cast<Expr*>(RHS), |
128 | Op, |
129 | C.getLogicalOperationType(), |
130 | VK_RValue, |
131 | OK_Ordinary, SourceLocation(), FPOptions()); |
132 | } |
133 | |
134 | CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) { |
135 | return CompoundStmt::Create(C, Stmts, SourceLocation(), SourceLocation()); |
136 | } |
137 | |
138 | DeclRefExpr *ASTMaker::makeDeclRefExpr( |
139 | const VarDecl *D, |
140 | bool RefersToEnclosingVariableOrCapture) { |
141 | QualType Type = D->getType().getNonReferenceType(); |
142 | |
143 | DeclRefExpr *DR = DeclRefExpr::Create( |
144 | C, NestedNameSpecifierLoc(), SourceLocation(), const_cast<VarDecl *>(D), |
145 | RefersToEnclosingVariableOrCapture, SourceLocation(), Type, VK_LValue); |
146 | return DR; |
147 | } |
148 | |
149 | UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) { |
150 | return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty, |
151 | VK_LValue, OK_Ordinary, SourceLocation(), |
152 | false); |
153 | } |
154 | |
155 | ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) { |
156 | return makeImplicitCast(Arg, Ty, CK_LValueToRValue); |
157 | } |
158 | |
159 | ImplicitCastExpr * |
160 | ASTMaker::makeLvalueToRvalue(const VarDecl *Arg, |
161 | bool RefersToEnclosingVariableOrCapture) { |
162 | QualType Type = Arg->getType().getNonReferenceType(); |
163 | return makeLvalueToRvalue(makeDeclRefExpr(Arg, |
164 | RefersToEnclosingVariableOrCapture), |
165 | Type); |
166 | } |
167 | |
168 | ImplicitCastExpr *ASTMaker::makeImplicitCast(const Expr *Arg, QualType Ty, |
169 | CastKind CK) { |
170 | return ImplicitCastExpr::Create(C, Ty, |
171 | CK, |
172 | const_cast<Expr *>(Arg), |
173 | nullptr, |
174 | VK_RValue); |
175 | } |
176 | |
177 | Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) { |
178 | if (Arg->getType() == Ty) |
179 | return const_cast<Expr*>(Arg); |
180 | |
181 | return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast, |
182 | const_cast<Expr*>(Arg), nullptr, VK_RValue); |
183 | } |
184 | |
185 | ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) { |
186 | return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean, |
187 | const_cast<Expr*>(Arg), nullptr, VK_RValue); |
188 | } |
189 | |
190 | ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) { |
191 | QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy; |
192 | return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation()); |
193 | } |
194 | |
195 | ObjCIvarRefExpr *ASTMaker::makeObjCIvarRef(const Expr *Base, |
196 | const ObjCIvarDecl *IVar) { |
197 | return new (C) ObjCIvarRefExpr(const_cast<ObjCIvarDecl*>(IVar), |
198 | IVar->getType(), SourceLocation(), |
199 | SourceLocation(), const_cast<Expr*>(Base), |
200 | , ); |
201 | } |
202 | |
203 | ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) { |
204 | return ReturnStmt::Create(C, SourceLocation(), const_cast<Expr *>(RetVal), |
205 | ); |
206 | } |
207 | |
208 | IntegerLiteral *ASTMaker::makeIntegerLiteral(uint64_t Value, QualType Ty) { |
209 | llvm::APInt APValue = llvm::APInt(C.getTypeSize(Ty), Value); |
210 | return IntegerLiteral::Create(C, APValue, Ty, SourceLocation()); |
211 | } |
212 | |
213 | MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl, |
214 | bool IsArrow, |
215 | ExprValueKind ValueKind) { |
216 | |
217 | DeclAccessPair FoundDecl = DeclAccessPair::make(MemberDecl, AS_public); |
218 | return MemberExpr::Create( |
219 | C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(), |
220 | SourceLocation(), MemberDecl, FoundDecl, |
221 | DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()), |
222 | nullptr, MemberDecl->getType(), ValueKind, |
223 | OK_Ordinary); |
224 | } |
225 | |
226 | ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) { |
227 | |
228 | CXXBasePaths Paths( |
229 | , |
230 | , |
231 | false); |
232 | const IdentifierInfo &II = C.Idents.get(Name); |
233 | DeclarationName DeclName = C.DeclarationNames.getIdentifier(&II); |
234 | |
235 | DeclContextLookupResult Decls = RD->lookup(DeclName); |
236 | for (NamedDecl *FoundDecl : Decls) |
237 | if (!FoundDecl->getDeclContext()->isFunctionOrMethod()) |
238 | return cast<ValueDecl>(FoundDecl); |
239 | |
240 | return nullptr; |
241 | } |
242 | |
243 | |
244 | |
245 | |
246 | |
247 | typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D); |
248 | |
249 | static CallExpr *create_call_once_funcptr_call(ASTContext &C, ASTMaker M, |
250 | const ParmVarDecl *Callback, |
251 | ArrayRef<Expr *> CallArgs) { |
252 | |
253 | QualType Ty = Callback->getType(); |
254 | DeclRefExpr *Call = M.makeDeclRefExpr(Callback); |
255 | Expr *SubExpr; |
256 | if (Ty->isRValueReferenceType()) { |
257 | SubExpr = M.makeImplicitCast( |
258 | Call, Ty.getNonReferenceType(), CK_LValueToRValue); |
259 | } else if (Ty->isLValueReferenceType() && |
260 | Call->getType()->isFunctionType()) { |
261 | Ty = C.getPointerType(Ty.getNonReferenceType()); |
262 | SubExpr = M.makeImplicitCast(Call, Ty, CK_FunctionToPointerDecay); |
263 | } else if (Ty->isLValueReferenceType() |
264 | && Call->getType()->isPointerType() |
265 | && Call->getType()->getPointeeType()->isFunctionType()){ |
266 | SubExpr = Call; |
267 | } else { |
268 | llvm_unreachable("Unexpected state"); |
269 | } |
270 | |
271 | return CallExpr::Create(C, SubExpr, CallArgs, C.VoidTy, VK_RValue, |
272 | SourceLocation()); |
273 | } |
274 | |
275 | static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M, |
276 | const ParmVarDecl *Callback, |
277 | CXXRecordDecl *CallbackDecl, |
278 | ArrayRef<Expr *> CallArgs) { |
279 | assert(CallbackDecl != nullptr); |
280 | isLambda()", "/home/seafit/code_projects/clang_source/clang/lib/Analysis/BodyFarm.cpp", 280, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(CallbackDecl->isLambda()); |
281 | FunctionDecl *callOperatorDecl = CallbackDecl->getLambdaCallOperator(); |
282 | assert(callOperatorDecl != nullptr); |
283 | |
284 | DeclRefExpr *callOperatorDeclRef = |
285 | DeclRefExpr::Create( C, |
286 | NestedNameSpecifierLoc(), |
287 | SourceLocation(), |
288 | const_cast<FunctionDecl *>(callOperatorDecl), |
289 | false, |
290 | SourceLocation(), |
291 | callOperatorDecl->getType(), |
292 | VK_LValue); |
293 | |
294 | return CXXOperatorCallExpr::Create( |
295 | C, OO_Call, callOperatorDeclRef, |
296 | CallArgs, |
297 | C.VoidTy, |
298 | VK_RValue, |
299 | SourceLocation(), FPOptions()); |
300 | } |
301 | |
302 | |
303 | |
304 | |
305 | |
306 | |
307 | |
308 | |
309 | |
310 | |
311 | |
312 | |
313 | |
314 | |
315 | |
316 | |
317 | static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { |
318 | LLVM_DEBUG(llvm::dbgs() << "Generating body for call_once\n"); |
319 | |
320 | |
321 | if (D->param_size() < 2) |
322 | return nullptr; |
323 | |
324 | ASTMaker M(C); |
325 | |
326 | const ParmVarDecl *Flag = D->getParamDecl(0); |
327 | const ParmVarDecl *Callback = D->getParamDecl(1); |
328 | |
329 | if (!Callback->getType()->isReferenceType()) { |
330 | llvm::dbgs() << "libcxx03 std::call_once implementation, skipping.\n"; |
331 | return nullptr; |
332 | } |
333 | if (!Flag->getType()->isReferenceType()) { |
334 | llvm::dbgs() << "unknown std::call_once implementation, skipping.\n"; |
335 | return nullptr; |
336 | } |
337 | |
338 | QualType CallbackType = Callback->getType().getNonReferenceType(); |
339 | |
340 | |
341 | CXXRecordDecl *CallbackRecordDecl = CallbackType->getAsCXXRecordDecl(); |
342 | QualType FlagType = Flag->getType().getNonReferenceType(); |
343 | auto *FlagRecordDecl = FlagType->getAsRecordDecl(); |
344 | |
345 | if (!FlagRecordDecl) { |
346 | LLVM_DEBUG(llvm::dbgs() << "Flag field is not a record: " |
347 | << "unknown std::call_once implementation, " |
348 | << "ignoring the call.\n"); |
349 | return nullptr; |
350 | } |
351 | |
352 | |
353 | |
354 | ValueDecl *FlagFieldDecl = M.findMemberField(FlagRecordDecl, "__state_"); |
355 | |
356 | |
357 | |
358 | if (!FlagFieldDecl) { |
359 | FlagFieldDecl = M.findMemberField(FlagRecordDecl, "_M_once"); |
360 | } |
361 | |
362 | if (!FlagFieldDecl) { |
363 | LLVM_DEBUG(llvm::dbgs() << "No field _M_once or __state_ found on " |
364 | << "std::once_flag struct: unknown std::call_once " |
365 | << "implementation, ignoring the call."); |
366 | return nullptr; |
367 | } |
368 | |
369 | bool isLambdaCall = CallbackRecordDecl && CallbackRecordDecl->isLambda(); |
370 | if (CallbackRecordDecl && !isLambdaCall) { |
371 | LLVM_DEBUG(llvm::dbgs() |
372 | << "Not supported: synthesizing body for functors when " |
373 | << "body farming std::call_once, ignoring the call."); |
374 | return nullptr; |
375 | } |
376 | |
377 | SmallVector<Expr *, 5> CallArgs; |
378 | const FunctionProtoType *CallbackFunctionType; |
379 | if (isLambdaCall) { |
380 | |
381 | |
382 | CallArgs.push_back( |
383 | M.makeDeclRefExpr(Callback, |
384 | true)); |
385 | CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator() |
386 | ->getType() |
387 | ->getAs<FunctionProtoType>(); |
388 | } else if (!CallbackType->getPointeeType().isNull()) { |
389 | CallbackFunctionType = |
390 | CallbackType->getPointeeType()->getAs<FunctionProtoType>(); |
391 | } else { |
392 | CallbackFunctionType = CallbackType->getAs<FunctionProtoType>(); |
393 | } |
394 | |
395 | if (!CallbackFunctionType) |
396 | return nullptr; |
397 | |
398 | |
399 | if (D->getNumParams() != CallbackFunctionType->getNumParams() + 2) { |
400 | LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match " |
401 | << "params passed to std::call_once, " |
402 | << "ignoring the call\n"); |
403 | return nullptr; |
404 | } |
405 | |
406 | |
407 | |
408 | |
409 | for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) { |
410 | const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx); |
411 | if (PDecl && |
412 | CallbackFunctionType->getParamType(ParamIdx - 2) |
413 | .getNonReferenceType() |
414 | .getCanonicalType() != |
415 | PDecl->getType().getNonReferenceType().getCanonicalType()) { |
416 | LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match " |
417 | << "params passed to std::call_once, " |
418 | << "ignoring the call\n"); |
419 | return nullptr; |
420 | } |
421 | Expr *ParamExpr = M.makeDeclRefExpr(PDecl); |
422 | if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) { |
423 | QualType PTy = PDecl->getType().getNonReferenceType(); |
424 | ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy); |
425 | } |
426 | CallArgs.push_back(ParamExpr); |
427 | } |
428 | |
429 | CallExpr *CallbackCall; |
430 | if (isLambdaCall) { |
431 | |
432 | CallbackCall = create_call_once_lambda_call(C, M, Callback, |
433 | CallbackRecordDecl, CallArgs); |
434 | } else { |
435 | |
436 | |
437 | CallbackCall = create_call_once_funcptr_call(C, M, Callback, CallArgs); |
438 | } |
439 | |
440 | DeclRefExpr *FlagDecl = |
441 | M.makeDeclRefExpr(Flag, |
442 | ); |
443 | |
444 | |
445 | MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl); |
446 | isLValue()", "/home/seafit/code_projects/clang_source/clang/lib/Analysis/BodyFarm.cpp", 446, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Deref->isLValue()); |
447 | QualType DerefType = Deref->getType(); |
448 | |
449 | |
450 | UnaryOperator *FlagCheck = new (C) UnaryOperator( |
451 | |
452 | M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType, |
453 | CK_IntegralToBoolean), |
454 | UO_LNot, |
455 | C.IntTy, |
456 | VK_RValue, |
457 | OK_Ordinary, SourceLocation(), |
458 | false); |
459 | |
460 | |
461 | BinaryOperator *FlagAssignment = M.makeAssignment( |
462 | Deref, M.makeIntegralCast(M.makeIntegerLiteral(1, C.IntTy), DerefType), |
463 | DerefType); |
464 | |
465 | auto *Out = |
466 | IfStmt::Create(C, SourceLocation(), |
467 | , |
468 | , |
469 | , |
470 | , |
471 | .makeCompound({CallbackCall, FlagAssignment})); |
472 | |
473 | return Out; |
474 | } |
475 | |
476 | |
477 | static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { |
478 | |
479 | if (D->param_size() != 2) |
480 | return nullptr; |
481 | |
482 | |
483 | const ParmVarDecl *Predicate = D->getParamDecl(0); |
484 | QualType PredicateQPtrTy = Predicate->getType(); |
485 | const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>(); |
486 | if (!PredicatePtrTy) |
487 | return nullptr; |
488 | QualType PredicateTy = PredicatePtrTy->getPointeeType(); |
489 | if (!PredicateTy->isIntegerType()) |
490 | return nullptr; |
491 | |
492 | |
493 | const ParmVarDecl *Block = D->getParamDecl(1); |
494 | QualType Ty = Block->getType(); |
495 | if (!isDispatchBlock(Ty)) |
496 | return nullptr; |
497 | |
498 | |
499 | |
500 | |
501 | |
502 | |
503 | |
504 | |
505 | |
506 | |
507 | |
508 | ASTMaker M(C); |
509 | |
510 | |
511 | CallExpr *CE = CallExpr::Create( |
512 | C, |
513 | M.makeLvalueToRvalue(Block), |
514 | None, |
515 | C.VoidTy, |
516 | VK_RValue, |
517 | SourceLocation()); |
518 | |
519 | |
520 | Expr *DoneValue = |
521 | new (C) UnaryOperator(M.makeIntegerLiteral(0, C.LongTy), UO_Not, C.LongTy, |
522 | VK_RValue, OK_Ordinary, SourceLocation(), |
523 | ); |
524 | |
525 | BinaryOperator *B = |
526 | M.makeAssignment( |
527 | M.makeDereference( |
528 | M.makeLvalueToRvalue( |
529 | M.makeDeclRefExpr(Predicate), PredicateQPtrTy), |
530 | PredicateTy), |
531 | M.makeIntegralCast(DoneValue, PredicateTy), |
532 | PredicateTy); |
533 | |
534 | |
535 | Stmt *Stmts[] = { B, CE }; |
536 | CompoundStmt *CS = M.makeCompound(Stmts); |
537 | |
538 | |
539 | ImplicitCastExpr *LValToRval = |
540 | M.makeLvalueToRvalue( |
541 | M.makeDereference( |
542 | M.makeLvalueToRvalue( |
543 | M.makeDeclRefExpr(Predicate), |
544 | PredicateQPtrTy), |
545 | PredicateTy), |
546 | PredicateTy); |
547 | |
548 | Expr *GuardCondition = M.makeComparison(LValToRval, DoneValue, BO_NE); |
549 | |
550 | auto *If = IfStmt::Create(C, SourceLocation(), |
551 | , |
552 | , |
553 | , |
554 | , |
555 | ); |
556 | return If; |
557 | } |
558 | |
559 | |
560 | static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) { |
561 | |
562 | if (D->param_size() != 2) |
563 | return nullptr; |
564 | |
565 | |
566 | const ParmVarDecl *PV = D->getParamDecl(1); |
567 | QualType Ty = PV->getType(); |
568 | if (!isDispatchBlock(Ty)) |
569 | return nullptr; |
570 | |
571 | |
572 | |
573 | |
574 | |
575 | |
576 | |
577 | |
578 | ASTMaker M(C); |
579 | DeclRefExpr *DR = M.makeDeclRefExpr(PV); |
580 | ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); |
581 | CallExpr *CE = |
582 | CallExpr::Create(C, ICE, None, C.VoidTy, VK_RValue, SourceLocation()); |
583 | return CE; |
584 | } |
585 | |
586 | static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D) |
587 | { |
588 | |
589 | if (D->param_size() != 3) |
590 | return nullptr; |
591 | |
592 | |
593 | |
594 | |
595 | |
596 | |
597 | |
598 | |
599 | |
600 | |
601 | |
602 | |
603 | QualType ResultTy = D->getReturnType(); |
604 | bool isBoolean = ResultTy->isBooleanType(); |
605 | if (!isBoolean && !ResultTy->isIntegralType(C)) |
606 | return nullptr; |
607 | |
608 | const ParmVarDecl *OldValue = D->getParamDecl(0); |
609 | QualType OldValueTy = OldValue->getType(); |
610 | |
611 | const ParmVarDecl *NewValue = D->getParamDecl(1); |
612 | QualType NewValueTy = NewValue->getType(); |
613 | |
614 | assert(OldValueTy == NewValueTy); |
615 | |
616 | const ParmVarDecl *TheValue = D->getParamDecl(2); |
617 | QualType TheValueTy = TheValue->getType(); |
618 | const PointerType *PT = TheValueTy->getAs<PointerType>(); |
619 | if (!PT) |
620 | return nullptr; |
621 | QualType PointeeTy = PT->getPointeeType(); |
622 | |
623 | ASTMaker M(C); |
624 | |
625 | Expr *Comparison = |
626 | M.makeComparison( |
627 | M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy), |
628 | M.makeLvalueToRvalue( |
629 | M.makeDereference( |
630 | M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy), |
631 | PointeeTy), |
632 | PointeeTy), |
633 | BO_EQ); |
634 | |
635 | |
636 | Stmt *Stmts[2]; |
637 | Stmts[0] = |
638 | M.makeAssignment( |
639 | M.makeDereference( |
640 | M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy), |
641 | PointeeTy), |
642 | M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy), |
643 | NewValueTy); |
644 | |
645 | Expr *BoolVal = M.makeObjCBool(true); |
646 | Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal) |
647 | : M.makeIntegralCast(BoolVal, ResultTy); |
648 | Stmts[1] = M.makeReturn(RetVal); |
649 | CompoundStmt *Body = M.makeCompound(Stmts); |
650 | |
651 | |
652 | BoolVal = M.makeObjCBool(false); |
653 | RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal) |
654 | : M.makeIntegralCast(BoolVal, ResultTy); |
655 | Stmt *Else = M.makeReturn(RetVal); |
656 | |
657 | |
658 | auto *If = IfStmt::Create(C, SourceLocation(), |
659 | , |
660 | , |
661 | , Comparison, Body, |
662 | SourceLocation(), Else); |
663 | |
664 | return If; |
665 | } |
666 | |
667 | Stmt *BodyFarm::getBody(const FunctionDecl *D) { |
668 | D = D->getCanonicalDecl(); |
669 | |
670 | Optional<Stmt *> &Val = Bodies[D]; |
671 | if (Val.hasValue()) |
672 | return Val.getValue(); |
673 | |
674 | Val = nullptr; |
675 | |
676 | if (D->getIdentifier() == nullptr) |
677 | return nullptr; |
678 | |
679 | StringRef Name = D->getName(); |
680 | if (Name.empty()) |
681 | return nullptr; |
682 | |
683 | FunctionFarmer FF; |
684 | |
685 | if (Name.startswith("OSAtomicCompareAndSwap") || |
686 | Name.startswith("objc_atomicCompareAndSwap")) { |
687 | FF = create_OSAtomicCompareAndSwap; |
688 | } else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) { |
689 | FF = create_call_once; |
690 | } else { |
691 | FF = llvm::StringSwitch<FunctionFarmer>(Name) |
692 | .Case("dispatch_sync", create_dispatch_sync) |
693 | .Case("dispatch_once", create_dispatch_once) |
694 | .Default(nullptr); |
695 | } |
696 | |
697 | if (FF) { Val = FF(C, D); } |
698 | else if (Injector) { Val = Injector->getBody(D); } |
699 | return Val.getValue(); |
700 | } |
701 | |
702 | static const ObjCIvarDecl *findBackingIvar(const ObjCPropertyDecl *Prop) { |
703 | const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl(); |
704 | |
705 | if (IVar) |
706 | return IVar; |
707 | |
708 | |
709 | |
710 | |
711 | |
712 | |
713 | |
714 | if (!Prop->isReadOnly()) |
715 | return nullptr; |
716 | |
717 | auto *Container = cast<ObjCContainerDecl>(Prop->getDeclContext()); |
718 | const ObjCInterfaceDecl *PrimaryInterface = nullptr; |
719 | if (auto *InterfaceDecl = dyn_cast<ObjCInterfaceDecl>(Container)) { |
720 | PrimaryInterface = InterfaceDecl; |
721 | } else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(Container)) { |
722 | PrimaryInterface = CategoryDecl->getClassInterface(); |
723 | } else if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) { |
724 | PrimaryInterface = ImplDecl->getClassInterface(); |
725 | } else { |
726 | return nullptr; |
727 | } |
728 | |
729 | |
730 | |
731 | |
732 | auto *ShadowingProp = PrimaryInterface->FindPropertyVisibleInPrimaryClass( |
733 | Prop->getIdentifier(), Prop->getQueryKind()); |
734 | if (ShadowingProp && ShadowingProp != Prop) { |
735 | IVar = ShadowingProp->getPropertyIvarDecl(); |
736 | } |
737 | |
738 | return IVar; |
739 | } |
740 | |
741 | static Stmt *createObjCPropertyGetter(ASTContext &Ctx, |
742 | const ObjCPropertyDecl *Prop) { |
743 | |
744 | const ObjCIvarDecl *IVar = findBackingIvar(Prop); |
745 | if (!IVar) |
746 | return nullptr; |
747 | |
748 | |
749 | if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak) |
750 | return nullptr; |
751 | |
752 | |
753 | |
754 | |
755 | |
756 | |
757 | const ObjCImplementationDecl *ImplDecl = |
758 | IVar->getContainingInterface()->getImplementation(); |
759 | if (ImplDecl) { |
760 | for (const auto *I : ImplDecl->property_impls()) { |
761 | if (I->getPropertyDecl() != Prop) |
762 | continue; |
763 | |
764 | if (I->getGetterCXXConstructor()) { |
765 | ASTMaker M(Ctx); |
766 | return M.makeReturn(I->getGetterCXXConstructor()); |
767 | } |
768 | } |
769 | } |
770 | |
771 | |
772 | |
773 | |
774 | if (!Ctx.hasSameUnqualifiedType(IVar->getType(), |
775 | Prop->getType().getNonReferenceType())) |
776 | return nullptr; |
777 | if (!IVar->getType()->isObjCLifetimeType() && |
778 | !IVar->getType().isTriviallyCopyableType(Ctx)) |
779 | return nullptr; |
780 | |
781 | |
782 | |
783 | ASTMaker M(Ctx); |
784 | |
785 | const VarDecl *selfVar = Prop->getGetterMethodDecl()->getSelfDecl(); |
786 | if (!selfVar) |
787 | return nullptr; |
788 | |
789 | Expr *loadedIVar = |
790 | M.makeObjCIvarRef( |
791 | M.makeLvalueToRvalue( |
792 | M.makeDeclRefExpr(selfVar), |
793 | selfVar->getType()), |
794 | IVar); |
795 | |
796 | if (!Prop->getType()->isReferenceType()) |
797 | loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType()); |
798 | |
799 | return M.makeReturn(loadedIVar); |
800 | } |
801 | |
802 | Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) { |
803 | |
804 | if (!D->isPropertyAccessor()) |
805 | return nullptr; |
806 | |
807 | D = D->getCanonicalDecl(); |
808 | |
809 | |
810 | |
811 | if (!D->isImplicit()) |
812 | return nullptr; |
813 | |
814 | Optional<Stmt *> &Val = Bodies[D]; |
815 | if (Val.hasValue()) |
816 | return Val.getValue(); |
817 | Val = nullptr; |
818 | |
819 | const ObjCPropertyDecl *Prop = D->findPropertyDecl(); |
820 | if (!Prop) |
821 | return nullptr; |
822 | |
823 | |
824 | |
825 | |
826 | |
827 | |
828 | |
829 | |
830 | |
831 | |
832 | if (D->param_size() != 0) |
833 | return nullptr; |
834 | |
835 | Val = createObjCPropertyGetter(C, Prop); |
836 | |
837 | return Val.getValue(); |
838 | } |
839 | |