Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Analysis/BodyFarm.cpp
35233 views
1
//== BodyFarm.cpp - Factory for conjuring up fake bodies ----------*- C++ -*-//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// BodyFarm is a factory for creating faux implementations for functions/methods
10
// for analysis purposes.
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/Builtins.h"
24
#include "clang/Basic/OperatorKinds.h"
25
#include "llvm/ADT/StringSwitch.h"
26
#include "llvm/Support/Debug.h"
27
#include <optional>
28
29
#define DEBUG_TYPE "body-farm"
30
31
using namespace clang;
32
33
//===----------------------------------------------------------------------===//
34
// Helper creation functions for constructing faux ASTs.
35
//===----------------------------------------------------------------------===//
36
37
static bool isDispatchBlock(QualType Ty) {
38
// Is it a block pointer?
39
const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
40
if (!BPT)
41
return false;
42
43
// Check if the block pointer type takes no arguments and
44
// returns void.
45
const FunctionProtoType *FT =
46
BPT->getPointeeType()->getAs<FunctionProtoType>();
47
return FT && FT->getReturnType()->isVoidType() && FT->getNumParams() == 0;
48
}
49
50
namespace {
51
class ASTMaker {
52
public:
53
ASTMaker(ASTContext &C) : C(C) {}
54
55
/// Create a new BinaryOperator representing a simple assignment.
56
BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty);
57
58
/// Create a new BinaryOperator representing a comparison.
59
BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS,
60
BinaryOperator::Opcode Op);
61
62
/// Create a new compound stmt using the provided statements.
63
CompoundStmt *makeCompound(ArrayRef<Stmt*>);
64
65
/// Create a new DeclRefExpr for the referenced variable.
66
DeclRefExpr *makeDeclRefExpr(const VarDecl *D,
67
bool RefersToEnclosingVariableOrCapture = false);
68
69
/// Create a new UnaryOperator representing a dereference.
70
UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);
71
72
/// Create an implicit cast for an integer conversion.
73
Expr *makeIntegralCast(const Expr *Arg, QualType Ty);
74
75
/// Create an implicit cast to a builtin boolean type.
76
ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg);
77
78
/// Create an implicit cast for lvalue-to-rvaluate conversions.
79
ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
80
81
/// Make RValue out of variable declaration, creating a temporary
82
/// DeclRefExpr in the process.
83
ImplicitCastExpr *
84
makeLvalueToRvalue(const VarDecl *Decl,
85
bool RefersToEnclosingVariableOrCapture = false);
86
87
/// Create an implicit cast of the given type.
88
ImplicitCastExpr *makeImplicitCast(const Expr *Arg, QualType Ty,
89
CastKind CK = CK_LValueToRValue);
90
91
/// Create a cast to reference type.
92
CastExpr *makeReferenceCast(const Expr *Arg, QualType Ty);
93
94
/// Create an Objective-C bool literal.
95
ObjCBoolLiteralExpr *makeObjCBool(bool Val);
96
97
/// Create an Objective-C ivar reference.
98
ObjCIvarRefExpr *makeObjCIvarRef(const Expr *Base, const ObjCIvarDecl *IVar);
99
100
/// Create a Return statement.
101
ReturnStmt *makeReturn(const Expr *RetVal);
102
103
/// Create an integer literal expression of the given type.
104
IntegerLiteral *makeIntegerLiteral(uint64_t Value, QualType Ty);
105
106
/// Create a member expression.
107
MemberExpr *makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
108
bool IsArrow = false,
109
ExprValueKind ValueKind = VK_LValue);
110
111
/// Returns a *first* member field of a record declaration with a given name.
112
/// \return an nullptr if no member with such a name exists.
113
ValueDecl *findMemberField(const RecordDecl *RD, StringRef Name);
114
115
private:
116
ASTContext &C;
117
};
118
}
119
120
BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
121
QualType Ty) {
122
return BinaryOperator::Create(
123
C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), BO_Assign, Ty,
124
VK_PRValue, OK_Ordinary, SourceLocation(), FPOptionsOverride());
125
}
126
127
BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
128
BinaryOperator::Opcode Op) {
129
assert(BinaryOperator::isLogicalOp(Op) ||
130
BinaryOperator::isComparisonOp(Op));
131
return BinaryOperator::Create(
132
C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), Op,
133
C.getLogicalOperationType(), VK_PRValue, OK_Ordinary, SourceLocation(),
134
FPOptionsOverride());
135
}
136
137
CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
138
return CompoundStmt::Create(C, Stmts, FPOptionsOverride(), SourceLocation(),
139
SourceLocation());
140
}
141
142
DeclRefExpr *ASTMaker::makeDeclRefExpr(
143
const VarDecl *D,
144
bool RefersToEnclosingVariableOrCapture) {
145
QualType Type = D->getType().getNonReferenceType();
146
147
DeclRefExpr *DR = DeclRefExpr::Create(
148
C, NestedNameSpecifierLoc(), SourceLocation(), const_cast<VarDecl *>(D),
149
RefersToEnclosingVariableOrCapture, SourceLocation(), Type, VK_LValue);
150
return DR;
151
}
152
153
UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
154
return UnaryOperator::Create(C, const_cast<Expr *>(Arg), UO_Deref, Ty,
155
VK_LValue, OK_Ordinary, SourceLocation(),
156
/*CanOverflow*/ false, FPOptionsOverride());
157
}
158
159
ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
160
return makeImplicitCast(Arg, Ty, CK_LValueToRValue);
161
}
162
163
ImplicitCastExpr *
164
ASTMaker::makeLvalueToRvalue(const VarDecl *Arg,
165
bool RefersToEnclosingVariableOrCapture) {
166
QualType Type = Arg->getType().getNonReferenceType();
167
return makeLvalueToRvalue(makeDeclRefExpr(Arg,
168
RefersToEnclosingVariableOrCapture),
169
Type);
170
}
171
172
ImplicitCastExpr *ASTMaker::makeImplicitCast(const Expr *Arg, QualType Ty,
173
CastKind CK) {
174
return ImplicitCastExpr::Create(C, Ty,
175
/* CastKind=*/CK,
176
/* Expr=*/const_cast<Expr *>(Arg),
177
/* CXXCastPath=*/nullptr,
178
/* ExprValueKind=*/VK_PRValue,
179
/* FPFeatures */ FPOptionsOverride());
180
}
181
182
CastExpr *ASTMaker::makeReferenceCast(const Expr *Arg, QualType Ty) {
183
assert(Ty->isReferenceType());
184
return CXXStaticCastExpr::Create(
185
C, Ty.getNonReferenceType(),
186
Ty->isLValueReferenceType() ? VK_LValue : VK_XValue, CK_NoOp,
187
const_cast<Expr *>(Arg), /*CXXCastPath=*/nullptr,
188
/*Written=*/C.getTrivialTypeSourceInfo(Ty), FPOptionsOverride(),
189
SourceLocation(), SourceLocation(), SourceRange());
190
}
191
192
Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
193
if (Arg->getType() == Ty)
194
return const_cast<Expr*>(Arg);
195
return makeImplicitCast(Arg, Ty, CK_IntegralCast);
196
}
197
198
ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {
199
return makeImplicitCast(Arg, C.BoolTy, CK_IntegralToBoolean);
200
}
201
202
ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
203
QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy;
204
return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());
205
}
206
207
ObjCIvarRefExpr *ASTMaker::makeObjCIvarRef(const Expr *Base,
208
const ObjCIvarDecl *IVar) {
209
return new (C) ObjCIvarRefExpr(const_cast<ObjCIvarDecl*>(IVar),
210
IVar->getType(), SourceLocation(),
211
SourceLocation(), const_cast<Expr*>(Base),
212
/*arrow=*/true, /*free=*/false);
213
}
214
215
ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
216
return ReturnStmt::Create(C, SourceLocation(), const_cast<Expr *>(RetVal),
217
/* NRVOCandidate=*/nullptr);
218
}
219
220
IntegerLiteral *ASTMaker::makeIntegerLiteral(uint64_t Value, QualType Ty) {
221
llvm::APInt APValue = llvm::APInt(C.getTypeSize(Ty), Value);
222
return IntegerLiteral::Create(C, APValue, Ty, SourceLocation());
223
}
224
225
MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
226
bool IsArrow,
227
ExprValueKind ValueKind) {
228
229
DeclAccessPair FoundDecl = DeclAccessPair::make(MemberDecl, AS_public);
230
return MemberExpr::Create(
231
C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(),
232
SourceLocation(), MemberDecl, FoundDecl,
233
DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()),
234
/* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind,
235
OK_Ordinary, NOUR_None);
236
}
237
238
ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) {
239
240
CXXBasePaths Paths(
241
/* FindAmbiguities=*/false,
242
/* RecordPaths=*/false,
243
/* DetectVirtual=*/ false);
244
const IdentifierInfo &II = C.Idents.get(Name);
245
DeclarationName DeclName = C.DeclarationNames.getIdentifier(&II);
246
247
DeclContextLookupResult Decls = RD->lookup(DeclName);
248
for (NamedDecl *FoundDecl : Decls)
249
if (!FoundDecl->getDeclContext()->isFunctionOrMethod())
250
return cast<ValueDecl>(FoundDecl);
251
252
return nullptr;
253
}
254
255
//===----------------------------------------------------------------------===//
256
// Creation functions for faux ASTs.
257
//===----------------------------------------------------------------------===//
258
259
typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
260
261
static CallExpr *create_call_once_funcptr_call(ASTContext &C, ASTMaker M,
262
const ParmVarDecl *Callback,
263
ArrayRef<Expr *> CallArgs) {
264
265
QualType Ty = Callback->getType();
266
DeclRefExpr *Call = M.makeDeclRefExpr(Callback);
267
Expr *SubExpr;
268
if (Ty->isRValueReferenceType()) {
269
SubExpr = M.makeImplicitCast(
270
Call, Ty.getNonReferenceType(), CK_LValueToRValue);
271
} else if (Ty->isLValueReferenceType() &&
272
Call->getType()->isFunctionType()) {
273
Ty = C.getPointerType(Ty.getNonReferenceType());
274
SubExpr = M.makeImplicitCast(Call, Ty, CK_FunctionToPointerDecay);
275
} else if (Ty->isLValueReferenceType()
276
&& Call->getType()->isPointerType()
277
&& Call->getType()->getPointeeType()->isFunctionType()){
278
SubExpr = Call;
279
} else {
280
llvm_unreachable("Unexpected state");
281
}
282
283
return CallExpr::Create(C, SubExpr, CallArgs, C.VoidTy, VK_PRValue,
284
SourceLocation(), FPOptionsOverride());
285
}
286
287
static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M,
288
const ParmVarDecl *Callback,
289
CXXRecordDecl *CallbackDecl,
290
ArrayRef<Expr *> CallArgs) {
291
assert(CallbackDecl != nullptr);
292
assert(CallbackDecl->isLambda());
293
FunctionDecl *callOperatorDecl = CallbackDecl->getLambdaCallOperator();
294
assert(callOperatorDecl != nullptr);
295
296
DeclRefExpr *callOperatorDeclRef =
297
DeclRefExpr::Create(/* Ctx =*/ C,
298
/* QualifierLoc =*/ NestedNameSpecifierLoc(),
299
/* TemplateKWLoc =*/ SourceLocation(),
300
const_cast<FunctionDecl *>(callOperatorDecl),
301
/* RefersToEnclosingVariableOrCapture=*/ false,
302
/* NameLoc =*/ SourceLocation(),
303
/* T =*/ callOperatorDecl->getType(),
304
/* VK =*/ VK_LValue);
305
306
return CXXOperatorCallExpr::Create(
307
/*AstContext=*/C, OO_Call, callOperatorDeclRef,
308
/*Args=*/CallArgs,
309
/*QualType=*/C.VoidTy,
310
/*ExprValueType=*/VK_PRValue,
311
/*SourceLocation=*/SourceLocation(),
312
/*FPFeatures=*/FPOptionsOverride());
313
}
314
315
/// Create a fake body for 'std::move' or 'std::forward'. This is just:
316
///
317
/// \code
318
/// return static_cast<return_type>(param);
319
/// \endcode
320
static Stmt *create_std_move_forward(ASTContext &C, const FunctionDecl *D) {
321
LLVM_DEBUG(llvm::dbgs() << "Generating body for std::move / std::forward\n");
322
323
ASTMaker M(C);
324
325
QualType ReturnType = D->getType()->castAs<FunctionType>()->getReturnType();
326
Expr *Param = M.makeDeclRefExpr(D->getParamDecl(0));
327
Expr *Cast = M.makeReferenceCast(Param, ReturnType);
328
return M.makeReturn(Cast);
329
}
330
331
/// Create a fake body for std::call_once.
332
/// Emulates the following function body:
333
///
334
/// \code
335
/// typedef struct once_flag_s {
336
/// unsigned long __state = 0;
337
/// } once_flag;
338
/// template<class Callable>
339
/// void call_once(once_flag& o, Callable func) {
340
/// if (!o.__state) {
341
/// func();
342
/// }
343
/// o.__state = 1;
344
/// }
345
/// \endcode
346
static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {
347
LLVM_DEBUG(llvm::dbgs() << "Generating body for call_once\n");
348
349
// We need at least two parameters.
350
if (D->param_size() < 2)
351
return nullptr;
352
353
ASTMaker M(C);
354
355
const ParmVarDecl *Flag = D->getParamDecl(0);
356
const ParmVarDecl *Callback = D->getParamDecl(1);
357
358
if (!Callback->getType()->isReferenceType()) {
359
llvm::dbgs() << "libcxx03 std::call_once implementation, skipping.\n";
360
return nullptr;
361
}
362
if (!Flag->getType()->isReferenceType()) {
363
llvm::dbgs() << "unknown std::call_once implementation, skipping.\n";
364
return nullptr;
365
}
366
367
QualType CallbackType = Callback->getType().getNonReferenceType();
368
369
// Nullable pointer, non-null iff function is a CXXRecordDecl.
370
CXXRecordDecl *CallbackRecordDecl = CallbackType->getAsCXXRecordDecl();
371
QualType FlagType = Flag->getType().getNonReferenceType();
372
auto *FlagRecordDecl = FlagType->getAsRecordDecl();
373
374
if (!FlagRecordDecl) {
375
LLVM_DEBUG(llvm::dbgs() << "Flag field is not a record: "
376
<< "unknown std::call_once implementation, "
377
<< "ignoring the call.\n");
378
return nullptr;
379
}
380
381
// We initially assume libc++ implementation of call_once,
382
// where the once_flag struct has a field `__state_`.
383
ValueDecl *FlagFieldDecl = M.findMemberField(FlagRecordDecl, "__state_");
384
385
// Otherwise, try libstdc++ implementation, with a field
386
// `_M_once`
387
if (!FlagFieldDecl) {
388
FlagFieldDecl = M.findMemberField(FlagRecordDecl, "_M_once");
389
}
390
391
if (!FlagFieldDecl) {
392
LLVM_DEBUG(llvm::dbgs() << "No field _M_once or __state_ found on "
393
<< "std::once_flag struct: unknown std::call_once "
394
<< "implementation, ignoring the call.");
395
return nullptr;
396
}
397
398
bool isLambdaCall = CallbackRecordDecl && CallbackRecordDecl->isLambda();
399
if (CallbackRecordDecl && !isLambdaCall) {
400
LLVM_DEBUG(llvm::dbgs()
401
<< "Not supported: synthesizing body for functors when "
402
<< "body farming std::call_once, ignoring the call.");
403
return nullptr;
404
}
405
406
SmallVector<Expr *, 5> CallArgs;
407
const FunctionProtoType *CallbackFunctionType;
408
if (isLambdaCall) {
409
410
// Lambda requires callback itself inserted as a first parameter.
411
CallArgs.push_back(
412
M.makeDeclRefExpr(Callback,
413
/* RefersToEnclosingVariableOrCapture=*/ true));
414
CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator()
415
->getType()
416
->getAs<FunctionProtoType>();
417
} else if (!CallbackType->getPointeeType().isNull()) {
418
CallbackFunctionType =
419
CallbackType->getPointeeType()->getAs<FunctionProtoType>();
420
} else {
421
CallbackFunctionType = CallbackType->getAs<FunctionProtoType>();
422
}
423
424
if (!CallbackFunctionType)
425
return nullptr;
426
427
// First two arguments are used for the flag and for the callback.
428
if (D->getNumParams() != CallbackFunctionType->getNumParams() + 2) {
429
LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match "
430
<< "params passed to std::call_once, "
431
<< "ignoring the call\n");
432
return nullptr;
433
}
434
435
// All arguments past first two ones are passed to the callback,
436
// and we turn lvalues into rvalues if the argument is not passed by
437
// reference.
438
for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) {
439
const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx);
440
assert(PDecl);
441
if (CallbackFunctionType->getParamType(ParamIdx - 2)
442
.getNonReferenceType()
443
.getCanonicalType() !=
444
PDecl->getType().getNonReferenceType().getCanonicalType()) {
445
LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match "
446
<< "params passed to std::call_once, "
447
<< "ignoring the call\n");
448
return nullptr;
449
}
450
Expr *ParamExpr = M.makeDeclRefExpr(PDecl);
451
if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) {
452
QualType PTy = PDecl->getType().getNonReferenceType();
453
ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy);
454
}
455
CallArgs.push_back(ParamExpr);
456
}
457
458
CallExpr *CallbackCall;
459
if (isLambdaCall) {
460
461
CallbackCall = create_call_once_lambda_call(C, M, Callback,
462
CallbackRecordDecl, CallArgs);
463
} else {
464
465
// Function pointer case.
466
CallbackCall = create_call_once_funcptr_call(C, M, Callback, CallArgs);
467
}
468
469
DeclRefExpr *FlagDecl =
470
M.makeDeclRefExpr(Flag,
471
/* RefersToEnclosingVariableOrCapture=*/true);
472
473
474
MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl);
475
assert(Deref->isLValue());
476
QualType DerefType = Deref->getType();
477
478
// Negation predicate.
479
UnaryOperator *FlagCheck = UnaryOperator::Create(
480
C,
481
/* input=*/
482
M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType,
483
CK_IntegralToBoolean),
484
/* opc=*/UO_LNot,
485
/* QualType=*/C.IntTy,
486
/* ExprValueKind=*/VK_PRValue,
487
/* ExprObjectKind=*/OK_Ordinary, SourceLocation(),
488
/* CanOverflow*/ false, FPOptionsOverride());
489
490
// Create assignment.
491
BinaryOperator *FlagAssignment = M.makeAssignment(
492
Deref, M.makeIntegralCast(M.makeIntegerLiteral(1, C.IntTy), DerefType),
493
DerefType);
494
495
auto *Out =
496
IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary,
497
/* Init=*/nullptr,
498
/* Var=*/nullptr,
499
/* Cond=*/FlagCheck,
500
/* LPL=*/SourceLocation(),
501
/* RPL=*/SourceLocation(),
502
/* Then=*/M.makeCompound({CallbackCall, FlagAssignment}));
503
504
return Out;
505
}
506
507
/// Create a fake body for dispatch_once.
508
static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
509
// Check if we have at least two parameters.
510
if (D->param_size() != 2)
511
return nullptr;
512
513
// Check if the first parameter is a pointer to integer type.
514
const ParmVarDecl *Predicate = D->getParamDecl(0);
515
QualType PredicateQPtrTy = Predicate->getType();
516
const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
517
if (!PredicatePtrTy)
518
return nullptr;
519
QualType PredicateTy = PredicatePtrTy->getPointeeType();
520
if (!PredicateTy->isIntegerType())
521
return nullptr;
522
523
// Check if the second parameter is the proper block type.
524
const ParmVarDecl *Block = D->getParamDecl(1);
525
QualType Ty = Block->getType();
526
if (!isDispatchBlock(Ty))
527
return nullptr;
528
529
// Everything checks out. Create a fakse body that checks the predicate,
530
// sets it, and calls the block. Basically, an AST dump of:
531
//
532
// void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
533
// if (*predicate != ~0l) {
534
// *predicate = ~0l;
535
// block();
536
// }
537
// }
538
539
ASTMaker M(C);
540
541
// (1) Create the call.
542
CallExpr *CE = CallExpr::Create(
543
/*ASTContext=*/C,
544
/*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Block),
545
/*Args=*/std::nullopt,
546
/*QualType=*/C.VoidTy,
547
/*ExprValueType=*/VK_PRValue,
548
/*SourceLocation=*/SourceLocation(), FPOptionsOverride());
549
550
// (2) Create the assignment to the predicate.
551
Expr *DoneValue =
552
UnaryOperator::Create(C, M.makeIntegerLiteral(0, C.LongTy), UO_Not,
553
C.LongTy, VK_PRValue, OK_Ordinary, SourceLocation(),
554
/*CanOverflow*/ false, FPOptionsOverride());
555
556
BinaryOperator *B =
557
M.makeAssignment(
558
M.makeDereference(
559
M.makeLvalueToRvalue(
560
M.makeDeclRefExpr(Predicate), PredicateQPtrTy),
561
PredicateTy),
562
M.makeIntegralCast(DoneValue, PredicateTy),
563
PredicateTy);
564
565
// (3) Create the compound statement.
566
Stmt *Stmts[] = { B, CE };
567
CompoundStmt *CS = M.makeCompound(Stmts);
568
569
// (4) Create the 'if' condition.
570
ImplicitCastExpr *LValToRval =
571
M.makeLvalueToRvalue(
572
M.makeDereference(
573
M.makeLvalueToRvalue(
574
M.makeDeclRefExpr(Predicate),
575
PredicateQPtrTy),
576
PredicateTy),
577
PredicateTy);
578
579
Expr *GuardCondition = M.makeComparison(LValToRval, DoneValue, BO_NE);
580
// (5) Create the 'if' statement.
581
auto *If = IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary,
582
/* Init=*/nullptr,
583
/* Var=*/nullptr,
584
/* Cond=*/GuardCondition,
585
/* LPL=*/SourceLocation(),
586
/* RPL=*/SourceLocation(),
587
/* Then=*/CS);
588
return If;
589
}
590
591
/// Create a fake body for dispatch_sync.
592
static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
593
// Check if we have at least two parameters.
594
if (D->param_size() != 2)
595
return nullptr;
596
597
// Check if the second parameter is a block.
598
const ParmVarDecl *PV = D->getParamDecl(1);
599
QualType Ty = PV->getType();
600
if (!isDispatchBlock(Ty))
601
return nullptr;
602
603
// Everything checks out. Create a fake body that just calls the block.
604
// This is basically just an AST dump of:
605
//
606
// void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
607
// block();
608
// }
609
//
610
ASTMaker M(C);
611
DeclRefExpr *DR = M.makeDeclRefExpr(PV);
612
ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
613
CallExpr *CE = CallExpr::Create(C, ICE, std::nullopt, C.VoidTy, VK_PRValue,
614
SourceLocation(), FPOptionsOverride());
615
return CE;
616
}
617
618
static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
619
{
620
// There are exactly 3 arguments.
621
if (D->param_size() != 3)
622
return nullptr;
623
624
// Signature:
625
// _Bool OSAtomicCompareAndSwapPtr(void *__oldValue,
626
// void *__newValue,
627
// void * volatile *__theValue)
628
// Generate body:
629
// if (oldValue == *theValue) {
630
// *theValue = newValue;
631
// return YES;
632
// }
633
// else return NO;
634
635
QualType ResultTy = D->getReturnType();
636
bool isBoolean = ResultTy->isBooleanType();
637
if (!isBoolean && !ResultTy->isIntegralType(C))
638
return nullptr;
639
640
const ParmVarDecl *OldValue = D->getParamDecl(0);
641
QualType OldValueTy = OldValue->getType();
642
643
const ParmVarDecl *NewValue = D->getParamDecl(1);
644
QualType NewValueTy = NewValue->getType();
645
646
assert(OldValueTy == NewValueTy);
647
648
const ParmVarDecl *TheValue = D->getParamDecl(2);
649
QualType TheValueTy = TheValue->getType();
650
const PointerType *PT = TheValueTy->getAs<PointerType>();
651
if (!PT)
652
return nullptr;
653
QualType PointeeTy = PT->getPointeeType();
654
655
ASTMaker M(C);
656
// Construct the comparison.
657
Expr *Comparison =
658
M.makeComparison(
659
M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy),
660
M.makeLvalueToRvalue(
661
M.makeDereference(
662
M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
663
PointeeTy),
664
PointeeTy),
665
BO_EQ);
666
667
// Construct the body of the IfStmt.
668
Stmt *Stmts[2];
669
Stmts[0] =
670
M.makeAssignment(
671
M.makeDereference(
672
M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
673
PointeeTy),
674
M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy),
675
NewValueTy);
676
677
Expr *BoolVal = M.makeObjCBool(true);
678
Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
679
: M.makeIntegralCast(BoolVal, ResultTy);
680
Stmts[1] = M.makeReturn(RetVal);
681
CompoundStmt *Body = M.makeCompound(Stmts);
682
683
// Construct the else clause.
684
BoolVal = M.makeObjCBool(false);
685
RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
686
: M.makeIntegralCast(BoolVal, ResultTy);
687
Stmt *Else = M.makeReturn(RetVal);
688
689
/// Construct the If.
690
auto *If =
691
IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary,
692
/* Init=*/nullptr,
693
/* Var=*/nullptr, Comparison,
694
/* LPL=*/SourceLocation(),
695
/* RPL=*/SourceLocation(), Body, SourceLocation(), Else);
696
697
return If;
698
}
699
700
Stmt *BodyFarm::getBody(const FunctionDecl *D) {
701
std::optional<Stmt *> &Val = Bodies[D];
702
if (Val)
703
return *Val;
704
705
Val = nullptr;
706
707
if (D->getIdentifier() == nullptr)
708
return nullptr;
709
710
StringRef Name = D->getName();
711
if (Name.empty())
712
return nullptr;
713
714
FunctionFarmer FF;
715
716
if (unsigned BuiltinID = D->getBuiltinID()) {
717
switch (BuiltinID) {
718
case Builtin::BIas_const:
719
case Builtin::BIforward:
720
case Builtin::BIforward_like:
721
case Builtin::BImove:
722
case Builtin::BImove_if_noexcept:
723
FF = create_std_move_forward;
724
break;
725
default:
726
FF = nullptr;
727
break;
728
}
729
} else if (Name.starts_with("OSAtomicCompareAndSwap") ||
730
Name.starts_with("objc_atomicCompareAndSwap")) {
731
FF = create_OSAtomicCompareAndSwap;
732
} else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) {
733
FF = create_call_once;
734
} else {
735
FF = llvm::StringSwitch<FunctionFarmer>(Name)
736
.Case("dispatch_sync", create_dispatch_sync)
737
.Case("dispatch_once", create_dispatch_once)
738
.Default(nullptr);
739
}
740
741
if (FF) { Val = FF(C, D); }
742
else if (Injector) { Val = Injector->getBody(D); }
743
return *Val;
744
}
745
746
static const ObjCIvarDecl *findBackingIvar(const ObjCPropertyDecl *Prop) {
747
const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();
748
749
if (IVar)
750
return IVar;
751
752
// When a readonly property is shadowed in a class extensions with a
753
// a readwrite property, the instance variable belongs to the shadowing
754
// property rather than the shadowed property. If there is no instance
755
// variable on a readonly property, check to see whether the property is
756
// shadowed and if so try to get the instance variable from shadowing
757
// property.
758
if (!Prop->isReadOnly())
759
return nullptr;
760
761
auto *Container = cast<ObjCContainerDecl>(Prop->getDeclContext());
762
const ObjCInterfaceDecl *PrimaryInterface = nullptr;
763
if (auto *InterfaceDecl = dyn_cast<ObjCInterfaceDecl>(Container)) {
764
PrimaryInterface = InterfaceDecl;
765
} else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(Container)) {
766
PrimaryInterface = CategoryDecl->getClassInterface();
767
} else if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) {
768
PrimaryInterface = ImplDecl->getClassInterface();
769
} else {
770
return nullptr;
771
}
772
773
// FindPropertyVisibleInPrimaryClass() looks first in class extensions, so it
774
// is guaranteed to find the shadowing property, if it exists, rather than
775
// the shadowed property.
776
auto *ShadowingProp = PrimaryInterface->FindPropertyVisibleInPrimaryClass(
777
Prop->getIdentifier(), Prop->getQueryKind());
778
if (ShadowingProp && ShadowingProp != Prop) {
779
IVar = ShadowingProp->getPropertyIvarDecl();
780
}
781
782
return IVar;
783
}
784
785
static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
786
const ObjCMethodDecl *MD) {
787
// First, find the backing ivar.
788
const ObjCIvarDecl *IVar = nullptr;
789
const ObjCPropertyDecl *Prop = nullptr;
790
791
// Property accessor stubs sometimes do not correspond to any property decl
792
// in the current interface (but in a superclass). They still have a
793
// corresponding property impl decl in this case.
794
if (MD->isSynthesizedAccessorStub()) {
795
const ObjCInterfaceDecl *IntD = MD->getClassInterface();
796
const ObjCImplementationDecl *ImpD = IntD->getImplementation();
797
for (const auto *PI : ImpD->property_impls()) {
798
if (const ObjCPropertyDecl *Candidate = PI->getPropertyDecl()) {
799
if (Candidate->getGetterName() == MD->getSelector()) {
800
Prop = Candidate;
801
IVar = Prop->getPropertyIvarDecl();
802
}
803
}
804
}
805
}
806
807
if (!IVar) {
808
Prop = MD->findPropertyDecl();
809
IVar = Prop ? findBackingIvar(Prop) : nullptr;
810
}
811
812
if (!IVar || !Prop)
813
return nullptr;
814
815
// Ignore weak variables, which have special behavior.
816
if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak)
817
return nullptr;
818
819
// Look to see if Sema has synthesized a body for us. This happens in
820
// Objective-C++ because the return value may be a C++ class type with a
821
// non-trivial copy constructor. We can only do this if we can find the
822
// @synthesize for this property, though (or if we know it's been auto-
823
// synthesized).
824
const ObjCImplementationDecl *ImplDecl =
825
IVar->getContainingInterface()->getImplementation();
826
if (ImplDecl) {
827
for (const auto *I : ImplDecl->property_impls()) {
828
if (I->getPropertyDecl() != Prop)
829
continue;
830
831
if (I->getGetterCXXConstructor()) {
832
ASTMaker M(Ctx);
833
return M.makeReturn(I->getGetterCXXConstructor());
834
}
835
}
836
}
837
838
// We expect that the property is the same type as the ivar, or a reference to
839
// it, and that it is either an object pointer or trivially copyable.
840
if (!Ctx.hasSameUnqualifiedType(IVar->getType(),
841
Prop->getType().getNonReferenceType()))
842
return nullptr;
843
if (!IVar->getType()->isObjCLifetimeType() &&
844
!IVar->getType().isTriviallyCopyableType(Ctx))
845
return nullptr;
846
847
// Generate our body:
848
// return self->_ivar;
849
ASTMaker M(Ctx);
850
851
const VarDecl *selfVar = MD->getSelfDecl();
852
if (!selfVar)
853
return nullptr;
854
855
Expr *loadedIVar = M.makeObjCIvarRef(
856
M.makeLvalueToRvalue(M.makeDeclRefExpr(selfVar), selfVar->getType()),
857
IVar);
858
859
if (!MD->getReturnType()->isReferenceType())
860
loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType());
861
862
return M.makeReturn(loadedIVar);
863
}
864
865
Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
866
// We currently only know how to synthesize property accessors.
867
if (!D->isPropertyAccessor())
868
return nullptr;
869
870
D = D->getCanonicalDecl();
871
872
// We should not try to synthesize explicitly redefined accessors.
873
// We do not know for sure how they behave.
874
if (!D->isImplicit())
875
return nullptr;
876
877
std::optional<Stmt *> &Val = Bodies[D];
878
if (Val)
879
return *Val;
880
Val = nullptr;
881
882
// For now, we only synthesize getters.
883
// Synthesizing setters would cause false negatives in the
884
// RetainCountChecker because the method body would bind the parameter
885
// to an instance variable, causing it to escape. This would prevent
886
// warning in the following common scenario:
887
//
888
// id foo = [[NSObject alloc] init];
889
// self.foo = foo; // We should warn that foo leaks here.
890
//
891
if (D->param_size() != 0)
892
return nullptr;
893
894
// If the property was defined in an extension, search the extensions for
895
// overrides.
896
const ObjCInterfaceDecl *OID = D->getClassInterface();
897
if (dyn_cast<ObjCInterfaceDecl>(D->getParent()) != OID)
898
for (auto *Ext : OID->known_extensions()) {
899
auto *OMD = Ext->getInstanceMethod(D->getSelector());
900
if (OMD && !OMD->isImplicit())
901
return nullptr;
902
}
903
904
Val = createObjCPropertyGetter(C, D);
905
906
return *Val;
907
}
908
909