1e8d8bef9SDimitry Andric //===- CalledOnceCheck.cpp - Check 'called once' parameters ---------------===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric 9e8d8bef9SDimitry Andric #include "clang/Analysis/Analyses/CalledOnceCheck.h" 10fe6060f1SDimitry Andric #include "clang/AST/ASTContext.h" 11e8d8bef9SDimitry Andric #include "clang/AST/Attr.h" 12e8d8bef9SDimitry Andric #include "clang/AST/Decl.h" 13e8d8bef9SDimitry Andric #include "clang/AST/DeclBase.h" 14e8d8bef9SDimitry Andric #include "clang/AST/Expr.h" 15e8d8bef9SDimitry Andric #include "clang/AST/ExprObjC.h" 16e8d8bef9SDimitry Andric #include "clang/AST/OperationKinds.h" 17e8d8bef9SDimitry Andric #include "clang/AST/ParentMap.h" 18e8d8bef9SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h" 19e8d8bef9SDimitry Andric #include "clang/AST/Stmt.h" 20e8d8bef9SDimitry Andric #include "clang/AST/StmtObjC.h" 21e8d8bef9SDimitry Andric #include "clang/AST/StmtVisitor.h" 22e8d8bef9SDimitry Andric #include "clang/AST/Type.h" 23e8d8bef9SDimitry Andric #include "clang/Analysis/AnalysisDeclContext.h" 24e8d8bef9SDimitry Andric #include "clang/Analysis/CFG.h" 25e8d8bef9SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowWorklist.h" 26fe6060f1SDimitry Andric #include "clang/Basic/Builtins.h" 27e8d8bef9SDimitry Andric #include "clang/Basic/IdentifierTable.h" 28e8d8bef9SDimitry Andric #include "clang/Basic/LLVM.h" 29e8d8bef9SDimitry Andric #include "llvm/ADT/BitVector.h" 30e8d8bef9SDimitry Andric #include "llvm/ADT/BitmaskEnum.h" 31e8d8bef9SDimitry Andric #include "llvm/ADT/PointerIntPair.h" 32e8d8bef9SDimitry Andric #include "llvm/ADT/STLExtras.h" 33e8d8bef9SDimitry Andric #include "llvm/ADT/Sequence.h" 34e8d8bef9SDimitry Andric #include "llvm/ADT/SmallVector.h" 35e8d8bef9SDimitry Andric #include "llvm/ADT/StringRef.h" 36e8d8bef9SDimitry Andric #include "llvm/Support/Casting.h" 37e8d8bef9SDimitry Andric #include "llvm/Support/Compiler.h" 38e8d8bef9SDimitry Andric #include "llvm/Support/ErrorHandling.h" 39e8d8bef9SDimitry Andric #include <memory> 40bdd1243dSDimitry Andric #include <optional> 41e8d8bef9SDimitry Andric 42e8d8bef9SDimitry Andric using namespace clang; 43e8d8bef9SDimitry Andric 44e8d8bef9SDimitry Andric namespace { 45e8d8bef9SDimitry Andric static constexpr unsigned EXPECTED_MAX_NUMBER_OF_PARAMS = 2; 46e8d8bef9SDimitry Andric template <class T> 47e8d8bef9SDimitry Andric using ParamSizedVector = llvm::SmallVector<T, EXPECTED_MAX_NUMBER_OF_PARAMS>; 48e8d8bef9SDimitry Andric static constexpr unsigned EXPECTED_NUMBER_OF_BASIC_BLOCKS = 8; 49e8d8bef9SDimitry Andric template <class T> 50e8d8bef9SDimitry Andric using CFGSizedVector = llvm::SmallVector<T, EXPECTED_NUMBER_OF_BASIC_BLOCKS>; 51e8d8bef9SDimitry Andric constexpr llvm::StringLiteral CONVENTIONAL_NAMES[] = { 52fe6060f1SDimitry Andric "completionHandler", "completion", "withCompletionHandler", 53fe6060f1SDimitry Andric "withCompletion", "completionBlock", "withCompletionBlock", 54fe6060f1SDimitry Andric "replyTo", "reply", "withReplyTo"}; 55e8d8bef9SDimitry Andric constexpr llvm::StringLiteral CONVENTIONAL_SUFFIXES[] = { 56fe6060f1SDimitry Andric "WithCompletionHandler", "WithCompletion", "WithCompletionBlock", 57fe6060f1SDimitry Andric "WithReplyTo", "WithReply"}; 58e8d8bef9SDimitry Andric constexpr llvm::StringLiteral CONVENTIONAL_CONDITIONS[] = { 59e8d8bef9SDimitry Andric "error", "cancel", "shouldCall", "done", "OK", "success"}; 60e8d8bef9SDimitry Andric 61fe6060f1SDimitry Andric struct KnownCalledOnceParameter { 62fe6060f1SDimitry Andric llvm::StringLiteral FunctionName; 63fe6060f1SDimitry Andric unsigned ParamIndex; 64fe6060f1SDimitry Andric }; 65fe6060f1SDimitry Andric constexpr KnownCalledOnceParameter KNOWN_CALLED_ONCE_PARAMETERS[] = { 66fe6060f1SDimitry Andric {llvm::StringLiteral{"dispatch_async"}, 1}, 67fe6060f1SDimitry Andric {llvm::StringLiteral{"dispatch_async_and_wait"}, 1}, 68fe6060f1SDimitry Andric {llvm::StringLiteral{"dispatch_after"}, 2}, 69fe6060f1SDimitry Andric {llvm::StringLiteral{"dispatch_sync"}, 1}, 70fe6060f1SDimitry Andric {llvm::StringLiteral{"dispatch_once"}, 1}, 71fe6060f1SDimitry Andric {llvm::StringLiteral{"dispatch_barrier_async"}, 1}, 72fe6060f1SDimitry Andric {llvm::StringLiteral{"dispatch_barrier_async_and_wait"}, 1}, 73fe6060f1SDimitry Andric {llvm::StringLiteral{"dispatch_barrier_sync"}, 1}}; 74fe6060f1SDimitry Andric 75e8d8bef9SDimitry Andric class ParameterStatus { 76e8d8bef9SDimitry Andric public: 77e8d8bef9SDimitry Andric // Status kind is basically the main part of parameter's status. 78e8d8bef9SDimitry Andric // The kind represents our knowledge (so far) about a tracked parameter 79e8d8bef9SDimitry Andric // in the context of this analysis. 80e8d8bef9SDimitry Andric // 81e8d8bef9SDimitry Andric // Since we want to report on missing and extraneous calls, we need to 82e8d8bef9SDimitry Andric // track the fact whether paramater was called or not. This automatically 83e8d8bef9SDimitry Andric // decides two kinds: `NotCalled` and `Called`. 84e8d8bef9SDimitry Andric // 85e8d8bef9SDimitry Andric // One of the erroneous situations is the case when parameter is called only 86e8d8bef9SDimitry Andric // on some of the paths. We could've considered it `NotCalled`, but we want 87e8d8bef9SDimitry Andric // to report double call warnings even if these two calls are not guaranteed 88e8d8bef9SDimitry Andric // to happen in every execution. We also don't want to have it as `Called` 89e8d8bef9SDimitry Andric // because not calling tracked parameter on all of the paths is an error 90e8d8bef9SDimitry Andric // on its own. For these reasons, we need to have a separate kind, 91e8d8bef9SDimitry Andric // `MaybeCalled`, and change `Called` to `DefinitelyCalled` to avoid 92e8d8bef9SDimitry Andric // confusion. 93e8d8bef9SDimitry Andric // 94e8d8bef9SDimitry Andric // Two violations of calling parameter more than once and not calling it on 95e8d8bef9SDimitry Andric // every path are not, however, mutually exclusive. In situations where both 96e8d8bef9SDimitry Andric // violations take place, we prefer to report ONLY double call. It's always 97e8d8bef9SDimitry Andric // harder to pinpoint a bug that has arisen when a user neglects to take the 98e8d8bef9SDimitry Andric // right action (and therefore, no action is taken), than when a user takes 99e8d8bef9SDimitry Andric // the wrong action. And, in order to remember that we already reported 100e8d8bef9SDimitry Andric // a double call, we need another kind: `Reported`. 101e8d8bef9SDimitry Andric // 102e8d8bef9SDimitry Andric // Our analysis is intra-procedural and, while in the perfect world, 103e8d8bef9SDimitry Andric // developers only use tracked parameters to call them, in the real world, 104e8d8bef9SDimitry Andric // the picture might be different. Parameters can be stored in global 105e8d8bef9SDimitry Andric // variables or leaked into other functions that we know nothing about. 106e8d8bef9SDimitry Andric // We try to be lenient and trust users. Another kind `Escaped` reflects 107e8d8bef9SDimitry Andric // such situations. We don't know if it gets called there or not, but we 108e8d8bef9SDimitry Andric // should always think of `Escaped` as the best possible option. 109e8d8bef9SDimitry Andric // 110e8d8bef9SDimitry Andric // Some of the paths in the analyzed functions might end with a call 111e8d8bef9SDimitry Andric // to noreturn functions. Such paths are not required to have parameter 112e8d8bef9SDimitry Andric // calls and we want to track that. For the purposes of better diagnostics, 113e8d8bef9SDimitry Andric // we don't want to reuse `Escaped` and, thus, have another kind `NoReturn`. 114e8d8bef9SDimitry Andric // 115e8d8bef9SDimitry Andric // Additionally, we have `NotVisited` kind that tells us nothing about 116e8d8bef9SDimitry Andric // a tracked parameter, but is used for tracking analyzed (aka visited) 117e8d8bef9SDimitry Andric // basic blocks. 118e8d8bef9SDimitry Andric // 119e8d8bef9SDimitry Andric // If we consider `|` to be a JOIN operation of two kinds coming from 120e8d8bef9SDimitry Andric // two different paths, the following properties must hold: 121e8d8bef9SDimitry Andric // 122e8d8bef9SDimitry Andric // 1. for any Kind K: K | K == K 123e8d8bef9SDimitry Andric // Joining two identical kinds should result in the same kind. 124e8d8bef9SDimitry Andric // 125e8d8bef9SDimitry Andric // 2. for any Kind K: Reported | K == Reported 126e8d8bef9SDimitry Andric // Doesn't matter on which path it was reported, it still is. 127e8d8bef9SDimitry Andric // 128e8d8bef9SDimitry Andric // 3. for any Kind K: NoReturn | K == K 129e8d8bef9SDimitry Andric // We can totally ignore noreturn paths during merges. 130e8d8bef9SDimitry Andric // 131e8d8bef9SDimitry Andric // 4. DefinitelyCalled | NotCalled == MaybeCalled 132e8d8bef9SDimitry Andric // Called on one path, not called on another - that's simply 133e8d8bef9SDimitry Andric // a definition for MaybeCalled. 134e8d8bef9SDimitry Andric // 135e8d8bef9SDimitry Andric // 5. for any Kind K in [DefinitelyCalled, NotCalled, MaybeCalled]: 136e8d8bef9SDimitry Andric // Escaped | K == K 137e8d8bef9SDimitry Andric // Escaped mirrors other statuses after joins. 138e8d8bef9SDimitry Andric // Every situation, when we join any of the listed kinds K, 139e8d8bef9SDimitry Andric // is a violation. For this reason, in order to assume the 140e8d8bef9SDimitry Andric // best outcome for this escape, we consider it to be the 141e8d8bef9SDimitry Andric // same as the other path. 142e8d8bef9SDimitry Andric // 143e8d8bef9SDimitry Andric // 6. for any Kind K in [DefinitelyCalled, NotCalled]: 144e8d8bef9SDimitry Andric // MaybeCalled | K == MaybeCalled 145e8d8bef9SDimitry Andric // MaybeCalled should basically stay after almost every join. 146e8d8bef9SDimitry Andric enum Kind { 147e8d8bef9SDimitry Andric // No-return paths should be absolutely transparent for the analysis. 148e8d8bef9SDimitry Andric // 0x0 is the identity element for selected join operation (binary or). 149e8d8bef9SDimitry Andric NoReturn = 0x0, /* 0000 */ 150e8d8bef9SDimitry Andric // Escaped marks situations when marked parameter escaped into 151e8d8bef9SDimitry Andric // another function (so we can assume that it was possibly called there). 152e8d8bef9SDimitry Andric Escaped = 0x1, /* 0001 */ 153e8d8bef9SDimitry Andric // Parameter was definitely called once at this point. 154e8d8bef9SDimitry Andric DefinitelyCalled = 0x3, /* 0011 */ 155e8d8bef9SDimitry Andric // Kinds less or equal to NON_ERROR_STATUS are not considered errors. 156e8d8bef9SDimitry Andric NON_ERROR_STATUS = DefinitelyCalled, 157e8d8bef9SDimitry Andric // Parameter was not yet called. 158e8d8bef9SDimitry Andric NotCalled = 0x5, /* 0101 */ 159e8d8bef9SDimitry Andric // Parameter was not called at least on one path leading to this point, 160e8d8bef9SDimitry Andric // while there is also at least one path that it gets called. 161e8d8bef9SDimitry Andric MaybeCalled = 0x7, /* 0111 */ 162e8d8bef9SDimitry Andric // Parameter was not yet analyzed. 163e8d8bef9SDimitry Andric NotVisited = 0x8, /* 1000 */ 164e8d8bef9SDimitry Andric // We already reported a violation and stopped tracking calls for this 165e8d8bef9SDimitry Andric // parameter. 166*0fca6ea1SDimitry Andric Reported = 0xF, /* 1111 */ 167e8d8bef9SDimitry Andric LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Reported) 168e8d8bef9SDimitry Andric }; 169e8d8bef9SDimitry Andric 170e8d8bef9SDimitry Andric constexpr ParameterStatus() = default; 171e8d8bef9SDimitry Andric /* implicit */ ParameterStatus(Kind K) : StatusKind(K) { 172e8d8bef9SDimitry Andric assert(!seenAnyCalls(K) && "Can't initialize status without a call"); 173e8d8bef9SDimitry Andric } 174e8d8bef9SDimitry Andric ParameterStatus(Kind K, const Expr *Call) : StatusKind(K), Call(Call) { 175e8d8bef9SDimitry Andric assert(seenAnyCalls(K) && "This kind is not supposed to have a call"); 176e8d8bef9SDimitry Andric } 177e8d8bef9SDimitry Andric 178e8d8bef9SDimitry Andric const Expr &getCall() const { 179e8d8bef9SDimitry Andric assert(seenAnyCalls(getKind()) && "ParameterStatus doesn't have a call"); 180e8d8bef9SDimitry Andric return *Call; 181e8d8bef9SDimitry Andric } 182e8d8bef9SDimitry Andric static bool seenAnyCalls(Kind K) { 183e8d8bef9SDimitry Andric return (K & DefinitelyCalled) == DefinitelyCalled && K != Reported; 184e8d8bef9SDimitry Andric } 185e8d8bef9SDimitry Andric bool seenAnyCalls() const { return seenAnyCalls(getKind()); } 186e8d8bef9SDimitry Andric 187e8d8bef9SDimitry Andric static bool isErrorStatus(Kind K) { return K > NON_ERROR_STATUS; } 188e8d8bef9SDimitry Andric bool isErrorStatus() const { return isErrorStatus(getKind()); } 189e8d8bef9SDimitry Andric 190e8d8bef9SDimitry Andric Kind getKind() const { return StatusKind; } 191e8d8bef9SDimitry Andric 192e8d8bef9SDimitry Andric void join(const ParameterStatus &Other) { 193e8d8bef9SDimitry Andric // If we have a pointer already, let's keep it. 194e8d8bef9SDimitry Andric // For the purposes of the analysis, it doesn't really matter 195e8d8bef9SDimitry Andric // which call we report. 196e8d8bef9SDimitry Andric // 197e8d8bef9SDimitry Andric // If we don't have a pointer, let's take whatever gets joined. 198e8d8bef9SDimitry Andric if (!Call) { 199e8d8bef9SDimitry Andric Call = Other.Call; 200e8d8bef9SDimitry Andric } 201e8d8bef9SDimitry Andric // Join kinds. 202e8d8bef9SDimitry Andric StatusKind |= Other.getKind(); 203e8d8bef9SDimitry Andric } 204e8d8bef9SDimitry Andric 205e8d8bef9SDimitry Andric bool operator==(const ParameterStatus &Other) const { 206e8d8bef9SDimitry Andric // We compare only kinds, pointers on their own is only additional 207e8d8bef9SDimitry Andric // information. 208e8d8bef9SDimitry Andric return getKind() == Other.getKind(); 209e8d8bef9SDimitry Andric } 210e8d8bef9SDimitry Andric 211e8d8bef9SDimitry Andric private: 212e8d8bef9SDimitry Andric // It would've been a perfect place to use llvm::PointerIntPair, but 213e8d8bef9SDimitry Andric // unfortunately NumLowBitsAvailable for clang::Expr had been reduced to 2. 214e8d8bef9SDimitry Andric Kind StatusKind = NotVisited; 215e8d8bef9SDimitry Andric const Expr *Call = nullptr; 216e8d8bef9SDimitry Andric }; 217e8d8bef9SDimitry Andric 218e8d8bef9SDimitry Andric /// State aggregates statuses of all tracked parameters. 219e8d8bef9SDimitry Andric class State { 220e8d8bef9SDimitry Andric public: 221e8d8bef9SDimitry Andric State(unsigned Size, ParameterStatus::Kind K = ParameterStatus::NotVisited) 222e8d8bef9SDimitry Andric : ParamData(Size, K) {} 223e8d8bef9SDimitry Andric 224e8d8bef9SDimitry Andric /// Return status of a parameter with the given index. 225e8d8bef9SDimitry Andric /// \{ 226e8d8bef9SDimitry Andric ParameterStatus &getStatusFor(unsigned Index) { return ParamData[Index]; } 227e8d8bef9SDimitry Andric const ParameterStatus &getStatusFor(unsigned Index) const { 228e8d8bef9SDimitry Andric return ParamData[Index]; 229e8d8bef9SDimitry Andric } 230e8d8bef9SDimitry Andric /// \} 231e8d8bef9SDimitry Andric 232e8d8bef9SDimitry Andric /// Return true if parameter with the given index can be called. 233e8d8bef9SDimitry Andric bool seenAnyCalls(unsigned Index) const { 234e8d8bef9SDimitry Andric return getStatusFor(Index).seenAnyCalls(); 235e8d8bef9SDimitry Andric } 236e8d8bef9SDimitry Andric /// Return a reference that we consider a call. 237e8d8bef9SDimitry Andric /// 238e8d8bef9SDimitry Andric /// Should only be used for parameters that can be called. 239e8d8bef9SDimitry Andric const Expr &getCallFor(unsigned Index) const { 240e8d8bef9SDimitry Andric return getStatusFor(Index).getCall(); 241e8d8bef9SDimitry Andric } 242e8d8bef9SDimitry Andric /// Return status kind of parameter with the given index. 243e8d8bef9SDimitry Andric ParameterStatus::Kind getKindFor(unsigned Index) const { 244e8d8bef9SDimitry Andric return getStatusFor(Index).getKind(); 245e8d8bef9SDimitry Andric } 246e8d8bef9SDimitry Andric 247e8d8bef9SDimitry Andric bool isVisited() const { 248e8d8bef9SDimitry Andric return llvm::all_of(ParamData, [](const ParameterStatus &S) { 249e8d8bef9SDimitry Andric return S.getKind() != ParameterStatus::NotVisited; 250e8d8bef9SDimitry Andric }); 251e8d8bef9SDimitry Andric } 252e8d8bef9SDimitry Andric 253e8d8bef9SDimitry Andric // Join other state into the current state. 254e8d8bef9SDimitry Andric void join(const State &Other) { 255e8d8bef9SDimitry Andric assert(ParamData.size() == Other.ParamData.size() && 256e8d8bef9SDimitry Andric "Couldn't join statuses with different sizes"); 257e8d8bef9SDimitry Andric for (auto Pair : llvm::zip(ParamData, Other.ParamData)) { 258e8d8bef9SDimitry Andric std::get<0>(Pair).join(std::get<1>(Pair)); 259e8d8bef9SDimitry Andric } 260e8d8bef9SDimitry Andric } 261e8d8bef9SDimitry Andric 262e8d8bef9SDimitry Andric using iterator = ParamSizedVector<ParameterStatus>::iterator; 263e8d8bef9SDimitry Andric using const_iterator = ParamSizedVector<ParameterStatus>::const_iterator; 264e8d8bef9SDimitry Andric 265e8d8bef9SDimitry Andric iterator begin() { return ParamData.begin(); } 266e8d8bef9SDimitry Andric iterator end() { return ParamData.end(); } 267e8d8bef9SDimitry Andric 268e8d8bef9SDimitry Andric const_iterator begin() const { return ParamData.begin(); } 269e8d8bef9SDimitry Andric const_iterator end() const { return ParamData.end(); } 270e8d8bef9SDimitry Andric 271e8d8bef9SDimitry Andric bool operator==(const State &Other) const { 272e8d8bef9SDimitry Andric return ParamData == Other.ParamData; 273e8d8bef9SDimitry Andric } 274e8d8bef9SDimitry Andric 275e8d8bef9SDimitry Andric private: 276e8d8bef9SDimitry Andric ParamSizedVector<ParameterStatus> ParamData; 277e8d8bef9SDimitry Andric }; 278e8d8bef9SDimitry Andric 279e8d8bef9SDimitry Andric /// A simple class that finds DeclRefExpr in the given expression. 280e8d8bef9SDimitry Andric /// 281e8d8bef9SDimitry Andric /// However, we don't want to find ANY nested DeclRefExpr skipping whatever 282e8d8bef9SDimitry Andric /// expressions on our way. Only certain expressions considered "no-op" 283e8d8bef9SDimitry Andric /// for our task are indeed skipped. 284e8d8bef9SDimitry Andric class DeclRefFinder 285e8d8bef9SDimitry Andric : public ConstStmtVisitor<DeclRefFinder, const DeclRefExpr *> { 286e8d8bef9SDimitry Andric public: 287e8d8bef9SDimitry Andric /// Find a DeclRefExpr in the given expression. 288e8d8bef9SDimitry Andric /// 289e8d8bef9SDimitry Andric /// In its most basic form (ShouldRetrieveFromComparisons == false), 290e8d8bef9SDimitry Andric /// this function can be simply reduced to the following question: 291e8d8bef9SDimitry Andric /// 292e8d8bef9SDimitry Andric /// - If expression E is used as a function argument, could we say 293e8d8bef9SDimitry Andric /// that DeclRefExpr nested in E is used as an argument? 294e8d8bef9SDimitry Andric /// 295e8d8bef9SDimitry Andric /// According to this rule, we can say that parens, casts and dereferencing 296e8d8bef9SDimitry Andric /// (dereferencing only applied to function pointers, but this is our case) 297e8d8bef9SDimitry Andric /// can be skipped. 298e8d8bef9SDimitry Andric /// 299e8d8bef9SDimitry Andric /// When we should look into comparisons the question changes to: 300e8d8bef9SDimitry Andric /// 301e8d8bef9SDimitry Andric /// - If expression E is used as a condition, could we say that 302e8d8bef9SDimitry Andric /// DeclRefExpr is being checked? 303e8d8bef9SDimitry Andric /// 304e8d8bef9SDimitry Andric /// And even though, these are two different questions, they have quite a lot 305e8d8bef9SDimitry Andric /// in common. Actually, we can say that whatever expression answers 306e8d8bef9SDimitry Andric /// positively the first question also fits the second question as well. 307e8d8bef9SDimitry Andric /// 308e8d8bef9SDimitry Andric /// In addition, we skip binary operators == and !=, and unary opeartor !. 309e8d8bef9SDimitry Andric static const DeclRefExpr *find(const Expr *E, 310e8d8bef9SDimitry Andric bool ShouldRetrieveFromComparisons = false) { 311e8d8bef9SDimitry Andric return DeclRefFinder(ShouldRetrieveFromComparisons).Visit(E); 312e8d8bef9SDimitry Andric } 313e8d8bef9SDimitry Andric 314e8d8bef9SDimitry Andric const DeclRefExpr *VisitDeclRefExpr(const DeclRefExpr *DR) { return DR; } 315e8d8bef9SDimitry Andric 316e8d8bef9SDimitry Andric const DeclRefExpr *VisitUnaryOperator(const UnaryOperator *UO) { 317e8d8bef9SDimitry Andric switch (UO->getOpcode()) { 318e8d8bef9SDimitry Andric case UO_LNot: 319e8d8bef9SDimitry Andric // We care about logical not only if we care about comparisons. 320e8d8bef9SDimitry Andric if (!ShouldRetrieveFromComparisons) 321e8d8bef9SDimitry Andric return nullptr; 322bdd1243dSDimitry Andric [[fallthrough]]; 323e8d8bef9SDimitry Andric // Function pointer/references can be dereferenced before a call. 324e8d8bef9SDimitry Andric // That doesn't make it, however, any different from a regular call. 325e8d8bef9SDimitry Andric // For this reason, dereference operation is a "no-op". 326e8d8bef9SDimitry Andric case UO_Deref: 327e8d8bef9SDimitry Andric return Visit(UO->getSubExpr()); 328e8d8bef9SDimitry Andric default: 329e8d8bef9SDimitry Andric return nullptr; 330e8d8bef9SDimitry Andric } 331e8d8bef9SDimitry Andric } 332e8d8bef9SDimitry Andric 333e8d8bef9SDimitry Andric const DeclRefExpr *VisitBinaryOperator(const BinaryOperator *BO) { 334e8d8bef9SDimitry Andric if (!ShouldRetrieveFromComparisons) 335e8d8bef9SDimitry Andric return nullptr; 336e8d8bef9SDimitry Andric 337e8d8bef9SDimitry Andric switch (BO->getOpcode()) { 338e8d8bef9SDimitry Andric case BO_EQ: 339e8d8bef9SDimitry Andric case BO_NE: { 340e8d8bef9SDimitry Andric const DeclRefExpr *LHS = Visit(BO->getLHS()); 341e8d8bef9SDimitry Andric return LHS ? LHS : Visit(BO->getRHS()); 342e8d8bef9SDimitry Andric } 343e8d8bef9SDimitry Andric default: 344e8d8bef9SDimitry Andric return nullptr; 345e8d8bef9SDimitry Andric } 346e8d8bef9SDimitry Andric } 347e8d8bef9SDimitry Andric 348e8d8bef9SDimitry Andric const DeclRefExpr *VisitOpaqueValueExpr(const OpaqueValueExpr *OVE) { 349e8d8bef9SDimitry Andric return Visit(OVE->getSourceExpr()); 350e8d8bef9SDimitry Andric } 351e8d8bef9SDimitry Andric 352fe6060f1SDimitry Andric const DeclRefExpr *VisitCallExpr(const CallExpr *CE) { 353fe6060f1SDimitry Andric if (!ShouldRetrieveFromComparisons) 354fe6060f1SDimitry Andric return nullptr; 355fe6060f1SDimitry Andric 356fe6060f1SDimitry Andric // We want to see through some of the boolean builtin functions 357fe6060f1SDimitry Andric // that we are likely to see in conditions. 358fe6060f1SDimitry Andric switch (CE->getBuiltinCallee()) { 359fe6060f1SDimitry Andric case Builtin::BI__builtin_expect: 360fe6060f1SDimitry Andric case Builtin::BI__builtin_expect_with_probability: { 361fe6060f1SDimitry Andric assert(CE->getNumArgs() >= 2); 362fe6060f1SDimitry Andric 363fe6060f1SDimitry Andric const DeclRefExpr *Candidate = Visit(CE->getArg(0)); 364fe6060f1SDimitry Andric return Candidate != nullptr ? Candidate : Visit(CE->getArg(1)); 365fe6060f1SDimitry Andric } 366fe6060f1SDimitry Andric 367fe6060f1SDimitry Andric case Builtin::BI__builtin_unpredictable: 368fe6060f1SDimitry Andric return Visit(CE->getArg(0)); 369fe6060f1SDimitry Andric 370fe6060f1SDimitry Andric default: 371fe6060f1SDimitry Andric return nullptr; 372fe6060f1SDimitry Andric } 373fe6060f1SDimitry Andric } 374fe6060f1SDimitry Andric 375e8d8bef9SDimitry Andric const DeclRefExpr *VisitExpr(const Expr *E) { 376e8d8bef9SDimitry Andric // It is a fallback method that gets called whenever the actual type 377e8d8bef9SDimitry Andric // of the given expression is not covered. 378e8d8bef9SDimitry Andric // 379e8d8bef9SDimitry Andric // We first check if we have anything to skip. And then repeat the whole 380e8d8bef9SDimitry Andric // procedure for a nested expression instead. 381e8d8bef9SDimitry Andric const Expr *DeclutteredExpr = E->IgnoreParenCasts(); 382e8d8bef9SDimitry Andric return E != DeclutteredExpr ? Visit(DeclutteredExpr) : nullptr; 383e8d8bef9SDimitry Andric } 384e8d8bef9SDimitry Andric 385e8d8bef9SDimitry Andric private: 386e8d8bef9SDimitry Andric DeclRefFinder(bool ShouldRetrieveFromComparisons) 387e8d8bef9SDimitry Andric : ShouldRetrieveFromComparisons(ShouldRetrieveFromComparisons) {} 388e8d8bef9SDimitry Andric 389e8d8bef9SDimitry Andric bool ShouldRetrieveFromComparisons; 390e8d8bef9SDimitry Andric }; 391e8d8bef9SDimitry Andric 392e8d8bef9SDimitry Andric const DeclRefExpr *findDeclRefExpr(const Expr *In, 393e8d8bef9SDimitry Andric bool ShouldRetrieveFromComparisons = false) { 394e8d8bef9SDimitry Andric return DeclRefFinder::find(In, ShouldRetrieveFromComparisons); 395e8d8bef9SDimitry Andric } 396e8d8bef9SDimitry Andric 397e8d8bef9SDimitry Andric const ParmVarDecl * 398e8d8bef9SDimitry Andric findReferencedParmVarDecl(const Expr *In, 399e8d8bef9SDimitry Andric bool ShouldRetrieveFromComparisons = false) { 400e8d8bef9SDimitry Andric if (const DeclRefExpr *DR = 401e8d8bef9SDimitry Andric findDeclRefExpr(In, ShouldRetrieveFromComparisons)) { 402e8d8bef9SDimitry Andric return dyn_cast<ParmVarDecl>(DR->getDecl()); 403e8d8bef9SDimitry Andric } 404e8d8bef9SDimitry Andric 405e8d8bef9SDimitry Andric return nullptr; 406e8d8bef9SDimitry Andric } 407e8d8bef9SDimitry Andric 408e8d8bef9SDimitry Andric /// Return conditions expression of a statement if it has one. 409e8d8bef9SDimitry Andric const Expr *getCondition(const Stmt *S) { 410e8d8bef9SDimitry Andric if (!S) { 411e8d8bef9SDimitry Andric return nullptr; 412e8d8bef9SDimitry Andric } 413e8d8bef9SDimitry Andric 414e8d8bef9SDimitry Andric if (const auto *If = dyn_cast<IfStmt>(S)) { 415e8d8bef9SDimitry Andric return If->getCond(); 416e8d8bef9SDimitry Andric } 417e8d8bef9SDimitry Andric if (const auto *Ternary = dyn_cast<AbstractConditionalOperator>(S)) { 418e8d8bef9SDimitry Andric return Ternary->getCond(); 419e8d8bef9SDimitry Andric } 420e8d8bef9SDimitry Andric 421e8d8bef9SDimitry Andric return nullptr; 422e8d8bef9SDimitry Andric } 423e8d8bef9SDimitry Andric 424e8d8bef9SDimitry Andric /// A small helper class that collects all named identifiers in the given 425e8d8bef9SDimitry Andric /// expression. It traverses it recursively, so names from deeper levels 426e8d8bef9SDimitry Andric /// of the AST will end up in the results. 427e8d8bef9SDimitry Andric /// Results might have duplicate names, if this is a problem, convert to 428e8d8bef9SDimitry Andric /// string sets afterwards. 429e8d8bef9SDimitry Andric class NamesCollector : public RecursiveASTVisitor<NamesCollector> { 430e8d8bef9SDimitry Andric public: 431e8d8bef9SDimitry Andric static constexpr unsigned EXPECTED_NUMBER_OF_NAMES = 5; 432e8d8bef9SDimitry Andric using NameCollection = 433e8d8bef9SDimitry Andric llvm::SmallVector<llvm::StringRef, EXPECTED_NUMBER_OF_NAMES>; 434e8d8bef9SDimitry Andric 435e8d8bef9SDimitry Andric static NameCollection collect(const Expr *From) { 436e8d8bef9SDimitry Andric NamesCollector Impl; 437e8d8bef9SDimitry Andric Impl.TraverseStmt(const_cast<Expr *>(From)); 438e8d8bef9SDimitry Andric return Impl.Result; 439e8d8bef9SDimitry Andric } 440e8d8bef9SDimitry Andric 441e8d8bef9SDimitry Andric bool VisitDeclRefExpr(const DeclRefExpr *E) { 442e8d8bef9SDimitry Andric Result.push_back(E->getDecl()->getName()); 443e8d8bef9SDimitry Andric return true; 444e8d8bef9SDimitry Andric } 445e8d8bef9SDimitry Andric 446e8d8bef9SDimitry Andric bool VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *E) { 447e8d8bef9SDimitry Andric llvm::StringRef Name; 448e8d8bef9SDimitry Andric 449e8d8bef9SDimitry Andric if (E->isImplicitProperty()) { 450e8d8bef9SDimitry Andric ObjCMethodDecl *PropertyMethodDecl = nullptr; 451e8d8bef9SDimitry Andric if (E->isMessagingGetter()) { 452e8d8bef9SDimitry Andric PropertyMethodDecl = E->getImplicitPropertyGetter(); 453e8d8bef9SDimitry Andric } else { 454e8d8bef9SDimitry Andric PropertyMethodDecl = E->getImplicitPropertySetter(); 455e8d8bef9SDimitry Andric } 456e8d8bef9SDimitry Andric assert(PropertyMethodDecl && 457e8d8bef9SDimitry Andric "Implicit property must have associated declaration"); 458e8d8bef9SDimitry Andric Name = PropertyMethodDecl->getSelector().getNameForSlot(0); 459e8d8bef9SDimitry Andric } else { 460e8d8bef9SDimitry Andric assert(E->isExplicitProperty()); 461e8d8bef9SDimitry Andric Name = E->getExplicitProperty()->getName(); 462e8d8bef9SDimitry Andric } 463e8d8bef9SDimitry Andric 464e8d8bef9SDimitry Andric Result.push_back(Name); 465e8d8bef9SDimitry Andric return true; 466e8d8bef9SDimitry Andric } 467e8d8bef9SDimitry Andric 468e8d8bef9SDimitry Andric private: 469e8d8bef9SDimitry Andric NamesCollector() = default; 470e8d8bef9SDimitry Andric NameCollection Result; 471e8d8bef9SDimitry Andric }; 472e8d8bef9SDimitry Andric 473e8d8bef9SDimitry Andric /// Check whether the given expression mentions any of conventional names. 474e8d8bef9SDimitry Andric bool mentionsAnyOfConventionalNames(const Expr *E) { 475e8d8bef9SDimitry Andric NamesCollector::NameCollection MentionedNames = NamesCollector::collect(E); 476e8d8bef9SDimitry Andric 477e8d8bef9SDimitry Andric return llvm::any_of(MentionedNames, [](llvm::StringRef ConditionName) { 478e8d8bef9SDimitry Andric return llvm::any_of( 479e8d8bef9SDimitry Andric CONVENTIONAL_CONDITIONS, 480e8d8bef9SDimitry Andric [ConditionName](const llvm::StringLiteral &Conventional) { 481fe6060f1SDimitry Andric return ConditionName.contains_insensitive(Conventional); 482e8d8bef9SDimitry Andric }); 483e8d8bef9SDimitry Andric }); 484e8d8bef9SDimitry Andric } 485e8d8bef9SDimitry Andric 486e8d8bef9SDimitry Andric /// Clarification is a simple pair of a reason why parameter is not called 487e8d8bef9SDimitry Andric /// on every path and a statement to blame. 488e8d8bef9SDimitry Andric struct Clarification { 489e8d8bef9SDimitry Andric NeverCalledReason Reason; 490e8d8bef9SDimitry Andric const Stmt *Location; 491e8d8bef9SDimitry Andric }; 492e8d8bef9SDimitry Andric 493e8d8bef9SDimitry Andric /// A helper class that can produce a clarification based on the given pair 494e8d8bef9SDimitry Andric /// of basic blocks. 495e8d8bef9SDimitry Andric class NotCalledClarifier 496e8d8bef9SDimitry Andric : public ConstStmtVisitor<NotCalledClarifier, 497bdd1243dSDimitry Andric std::optional<Clarification>> { 498e8d8bef9SDimitry Andric public: 499e8d8bef9SDimitry Andric /// The main entrypoint for the class, the function that tries to find the 500e8d8bef9SDimitry Andric /// clarification of how to explain which sub-path starts with a CFG edge 501e8d8bef9SDimitry Andric /// from Conditional to SuccWithoutCall. 502e8d8bef9SDimitry Andric /// 503e8d8bef9SDimitry Andric /// This means that this function has one precondition: 504e8d8bef9SDimitry Andric /// SuccWithoutCall should be a successor block for Conditional. 505e8d8bef9SDimitry Andric /// 506e8d8bef9SDimitry Andric /// Because clarification is not needed for non-trivial pairs of blocks 507e8d8bef9SDimitry Andric /// (i.e. SuccWithoutCall is not the only successor), it returns meaningful 508e8d8bef9SDimitry Andric /// results only for such cases. For this very reason, the parent basic 509e8d8bef9SDimitry Andric /// block, Conditional, is named that way, so it is clear what kind of 510e8d8bef9SDimitry Andric /// block is expected. 511bdd1243dSDimitry Andric static std::optional<Clarification> clarify(const CFGBlock *Conditional, 512bdd1243dSDimitry Andric const CFGBlock *SuccWithoutCall) { 513e8d8bef9SDimitry Andric if (const Stmt *Terminator = Conditional->getTerminatorStmt()) { 514e8d8bef9SDimitry Andric return NotCalledClarifier{Conditional, SuccWithoutCall}.Visit(Terminator); 515e8d8bef9SDimitry Andric } 516bdd1243dSDimitry Andric return std::nullopt; 517e8d8bef9SDimitry Andric } 518e8d8bef9SDimitry Andric 519bdd1243dSDimitry Andric std::optional<Clarification> VisitIfStmt(const IfStmt *If) { 520e8d8bef9SDimitry Andric return VisitBranchingBlock(If, NeverCalledReason::IfThen); 521e8d8bef9SDimitry Andric } 522e8d8bef9SDimitry Andric 523bdd1243dSDimitry Andric std::optional<Clarification> 524e8d8bef9SDimitry Andric VisitAbstractConditionalOperator(const AbstractConditionalOperator *Ternary) { 525e8d8bef9SDimitry Andric return VisitBranchingBlock(Ternary, NeverCalledReason::IfThen); 526e8d8bef9SDimitry Andric } 527e8d8bef9SDimitry Andric 528bdd1243dSDimitry Andric std::optional<Clarification> VisitSwitchStmt(const SwitchStmt *Switch) { 529e8d8bef9SDimitry Andric const Stmt *CaseToBlame = SuccInQuestion->getLabel(); 530e8d8bef9SDimitry Andric if (!CaseToBlame) { 531e8d8bef9SDimitry Andric // If interesting basic block is not labeled, it means that this 532e8d8bef9SDimitry Andric // basic block does not represent any of the cases. 533e8d8bef9SDimitry Andric return Clarification{NeverCalledReason::SwitchSkipped, Switch}; 534e8d8bef9SDimitry Andric } 535e8d8bef9SDimitry Andric 536e8d8bef9SDimitry Andric for (const SwitchCase *Case = Switch->getSwitchCaseList(); Case; 537e8d8bef9SDimitry Andric Case = Case->getNextSwitchCase()) { 538e8d8bef9SDimitry Andric if (Case == CaseToBlame) { 539e8d8bef9SDimitry Andric return Clarification{NeverCalledReason::Switch, Case}; 540e8d8bef9SDimitry Andric } 541e8d8bef9SDimitry Andric } 542e8d8bef9SDimitry Andric 543e8d8bef9SDimitry Andric llvm_unreachable("Found unexpected switch structure"); 544e8d8bef9SDimitry Andric } 545e8d8bef9SDimitry Andric 546bdd1243dSDimitry Andric std::optional<Clarification> VisitForStmt(const ForStmt *For) { 547e8d8bef9SDimitry Andric return VisitBranchingBlock(For, NeverCalledReason::LoopEntered); 548e8d8bef9SDimitry Andric } 549e8d8bef9SDimitry Andric 550bdd1243dSDimitry Andric std::optional<Clarification> VisitWhileStmt(const WhileStmt *While) { 551e8d8bef9SDimitry Andric return VisitBranchingBlock(While, NeverCalledReason::LoopEntered); 552e8d8bef9SDimitry Andric } 553e8d8bef9SDimitry Andric 554bdd1243dSDimitry Andric std::optional<Clarification> 555e8d8bef9SDimitry Andric VisitBranchingBlock(const Stmt *Terminator, NeverCalledReason DefaultReason) { 556e8d8bef9SDimitry Andric assert(Parent->succ_size() == 2 && 557e8d8bef9SDimitry Andric "Branching block should have exactly two successors"); 558e8d8bef9SDimitry Andric unsigned SuccessorIndex = getSuccessorIndex(Parent, SuccInQuestion); 559e8d8bef9SDimitry Andric NeverCalledReason ActualReason = 560e8d8bef9SDimitry Andric updateForSuccessor(DefaultReason, SuccessorIndex); 561e8d8bef9SDimitry Andric return Clarification{ActualReason, Terminator}; 562e8d8bef9SDimitry Andric } 563e8d8bef9SDimitry Andric 564bdd1243dSDimitry Andric std::optional<Clarification> VisitBinaryOperator(const BinaryOperator *) { 565e8d8bef9SDimitry Andric // We don't want to report on short-curcuit logical operations. 566bdd1243dSDimitry Andric return std::nullopt; 567e8d8bef9SDimitry Andric } 568e8d8bef9SDimitry Andric 569bdd1243dSDimitry Andric std::optional<Clarification> VisitStmt(const Stmt *Terminator) { 570e8d8bef9SDimitry Andric // If we got here, we didn't have a visit function for more derived 571e8d8bef9SDimitry Andric // classes of statement that this terminator actually belongs to. 572e8d8bef9SDimitry Andric // 573e8d8bef9SDimitry Andric // This is not a good scenario and should not happen in practice, but 574e8d8bef9SDimitry Andric // at least we'll warn the user. 575e8d8bef9SDimitry Andric return Clarification{NeverCalledReason::FallbackReason, Terminator}; 576e8d8bef9SDimitry Andric } 577e8d8bef9SDimitry Andric 578e8d8bef9SDimitry Andric static unsigned getSuccessorIndex(const CFGBlock *Parent, 579e8d8bef9SDimitry Andric const CFGBlock *Child) { 580e8d8bef9SDimitry Andric CFGBlock::const_succ_iterator It = llvm::find(Parent->succs(), Child); 581e8d8bef9SDimitry Andric assert(It != Parent->succ_end() && 582e8d8bef9SDimitry Andric "Given blocks should be in parent-child relationship"); 583e8d8bef9SDimitry Andric return It - Parent->succ_begin(); 584e8d8bef9SDimitry Andric } 585e8d8bef9SDimitry Andric 586e8d8bef9SDimitry Andric static NeverCalledReason 587e8d8bef9SDimitry Andric updateForSuccessor(NeverCalledReason ReasonForTrueBranch, 588e8d8bef9SDimitry Andric unsigned SuccessorIndex) { 589e8d8bef9SDimitry Andric assert(SuccessorIndex <= 1); 590e8d8bef9SDimitry Andric unsigned RawReason = 591e8d8bef9SDimitry Andric static_cast<unsigned>(ReasonForTrueBranch) + SuccessorIndex; 592e8d8bef9SDimitry Andric assert(RawReason <= 593e8d8bef9SDimitry Andric static_cast<unsigned>(NeverCalledReason::LARGEST_VALUE)); 594e8d8bef9SDimitry Andric return static_cast<NeverCalledReason>(RawReason); 595e8d8bef9SDimitry Andric } 596e8d8bef9SDimitry Andric 597e8d8bef9SDimitry Andric private: 598e8d8bef9SDimitry Andric NotCalledClarifier(const CFGBlock *Parent, const CFGBlock *SuccInQuestion) 599e8d8bef9SDimitry Andric : Parent(Parent), SuccInQuestion(SuccInQuestion) {} 600e8d8bef9SDimitry Andric 601e8d8bef9SDimitry Andric const CFGBlock *Parent, *SuccInQuestion; 602e8d8bef9SDimitry Andric }; 603e8d8bef9SDimitry Andric 604e8d8bef9SDimitry Andric class CalledOnceChecker : public ConstStmtVisitor<CalledOnceChecker> { 605e8d8bef9SDimitry Andric public: 606e8d8bef9SDimitry Andric static void check(AnalysisDeclContext &AC, CalledOnceCheckHandler &Handler, 607e8d8bef9SDimitry Andric bool CheckConventionalParameters) { 608e8d8bef9SDimitry Andric CalledOnceChecker(AC, Handler, CheckConventionalParameters).check(); 609e8d8bef9SDimitry Andric } 610e8d8bef9SDimitry Andric 611e8d8bef9SDimitry Andric private: 612e8d8bef9SDimitry Andric CalledOnceChecker(AnalysisDeclContext &AC, CalledOnceCheckHandler &Handler, 613e8d8bef9SDimitry Andric bool CheckConventionalParameters) 614e8d8bef9SDimitry Andric : FunctionCFG(*AC.getCFG()), AC(AC), Handler(Handler), 615e8d8bef9SDimitry Andric CheckConventionalParameters(CheckConventionalParameters), 616e8d8bef9SDimitry Andric CurrentState(0) { 617e8d8bef9SDimitry Andric initDataStructures(); 618e8d8bef9SDimitry Andric assert((size() == 0 || !States.empty()) && 619e8d8bef9SDimitry Andric "Data structures are inconsistent"); 620e8d8bef9SDimitry Andric } 621e8d8bef9SDimitry Andric 622e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 623e8d8bef9SDimitry Andric // Initializing functions 624e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 625e8d8bef9SDimitry Andric 626e8d8bef9SDimitry Andric void initDataStructures() { 627e8d8bef9SDimitry Andric const Decl *AnalyzedDecl = AC.getDecl(); 628e8d8bef9SDimitry Andric 629e8d8bef9SDimitry Andric if (const auto *Function = dyn_cast<FunctionDecl>(AnalyzedDecl)) { 630e8d8bef9SDimitry Andric findParamsToTrack(Function); 631e8d8bef9SDimitry Andric } else if (const auto *Method = dyn_cast<ObjCMethodDecl>(AnalyzedDecl)) { 632e8d8bef9SDimitry Andric findParamsToTrack(Method); 633e8d8bef9SDimitry Andric } else if (const auto *Block = dyn_cast<BlockDecl>(AnalyzedDecl)) { 634e8d8bef9SDimitry Andric findCapturesToTrack(Block); 635e8d8bef9SDimitry Andric findParamsToTrack(Block); 636e8d8bef9SDimitry Andric } 637e8d8bef9SDimitry Andric 638e8d8bef9SDimitry Andric // Have something to track, let's init states for every block from the CFG. 639e8d8bef9SDimitry Andric if (size() != 0) { 640e8d8bef9SDimitry Andric States = 641e8d8bef9SDimitry Andric CFGSizedVector<State>(FunctionCFG.getNumBlockIDs(), State(size())); 642e8d8bef9SDimitry Andric } 643e8d8bef9SDimitry Andric } 644e8d8bef9SDimitry Andric 645e8d8bef9SDimitry Andric void findCapturesToTrack(const BlockDecl *Block) { 646e8d8bef9SDimitry Andric for (const auto &Capture : Block->captures()) { 647e8d8bef9SDimitry Andric if (const auto *P = dyn_cast<ParmVarDecl>(Capture.getVariable())) { 648e8d8bef9SDimitry Andric // Parameter DeclContext is its owning function or method. 649e8d8bef9SDimitry Andric const DeclContext *ParamContext = P->getDeclContext(); 650e8d8bef9SDimitry Andric if (shouldBeCalledOnce(ParamContext, P)) { 651e8d8bef9SDimitry Andric TrackedParams.push_back(P); 652e8d8bef9SDimitry Andric } 653e8d8bef9SDimitry Andric } 654e8d8bef9SDimitry Andric } 655e8d8bef9SDimitry Andric } 656e8d8bef9SDimitry Andric 657e8d8bef9SDimitry Andric template <class FunctionLikeDecl> 658e8d8bef9SDimitry Andric void findParamsToTrack(const FunctionLikeDecl *Function) { 659e8d8bef9SDimitry Andric for (unsigned Index : llvm::seq<unsigned>(0u, Function->param_size())) { 660e8d8bef9SDimitry Andric if (shouldBeCalledOnce(Function, Index)) { 661e8d8bef9SDimitry Andric TrackedParams.push_back(Function->getParamDecl(Index)); 662e8d8bef9SDimitry Andric } 663e8d8bef9SDimitry Andric } 664e8d8bef9SDimitry Andric } 665e8d8bef9SDimitry Andric 666e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 667e8d8bef9SDimitry Andric // Main logic 'check' functions 668e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 669e8d8bef9SDimitry Andric 670e8d8bef9SDimitry Andric void check() { 671e8d8bef9SDimitry Andric // Nothing to check here: we don't have marked parameters. 672e8d8bef9SDimitry Andric if (size() == 0 || isPossiblyEmptyImpl()) 673e8d8bef9SDimitry Andric return; 674e8d8bef9SDimitry Andric 675e8d8bef9SDimitry Andric assert( 676e8d8bef9SDimitry Andric llvm::none_of(States, [](const State &S) { return S.isVisited(); }) && 677e8d8bef9SDimitry Andric "None of the blocks should be 'visited' before the analysis"); 678e8d8bef9SDimitry Andric 679e8d8bef9SDimitry Andric // For our task, both backward and forward approaches suite well. 680e8d8bef9SDimitry Andric // However, in order to report better diagnostics, we decided to go with 681e8d8bef9SDimitry Andric // backward analysis. 682e8d8bef9SDimitry Andric // 683e8d8bef9SDimitry Andric // Let's consider the following CFG and how forward and backward analyses 684e8d8bef9SDimitry Andric // will work for it. 685e8d8bef9SDimitry Andric // 686e8d8bef9SDimitry Andric // FORWARD: | BACKWARD: 687e8d8bef9SDimitry Andric // #1 | #1 688e8d8bef9SDimitry Andric // +---------+ | +-----------+ 689e8d8bef9SDimitry Andric // | if | | |MaybeCalled| 690e8d8bef9SDimitry Andric // +---------+ | +-----------+ 691e8d8bef9SDimitry Andric // |NotCalled| | | if | 692e8d8bef9SDimitry Andric // +---------+ | +-----------+ 693e8d8bef9SDimitry Andric // / \ | / \ 694e8d8bef9SDimitry Andric // #2 / \ #3 | #2 / \ #3 695e8d8bef9SDimitry Andric // +----------------+ +---------+ | +----------------+ +---------+ 696e8d8bef9SDimitry Andric // | foo() | | ... | | |DefinitelyCalled| |NotCalled| 697e8d8bef9SDimitry Andric // +----------------+ +---------+ | +----------------+ +---------+ 698e8d8bef9SDimitry Andric // |DefinitelyCalled| |NotCalled| | | foo() | | ... | 699e8d8bef9SDimitry Andric // +----------------+ +---------+ | +----------------+ +---------+ 700e8d8bef9SDimitry Andric // \ / | \ / 701e8d8bef9SDimitry Andric // \ #4 / | \ #4 / 702e8d8bef9SDimitry Andric // +-----------+ | +---------+ 703e8d8bef9SDimitry Andric // | ... | | |NotCalled| 704e8d8bef9SDimitry Andric // +-----------+ | +---------+ 705e8d8bef9SDimitry Andric // |MaybeCalled| | | ... | 706e8d8bef9SDimitry Andric // +-----------+ | +---------+ 707e8d8bef9SDimitry Andric // 708e8d8bef9SDimitry Andric // The most natural way to report lacking call in the block #3 would be to 709e8d8bef9SDimitry Andric // message that the false branch of the if statement in the block #1 doesn't 710e8d8bef9SDimitry Andric // have a call. And while with the forward approach we'll need to find a 711e8d8bef9SDimitry Andric // least common ancestor or something like that to find the 'if' to blame, 712e8d8bef9SDimitry Andric // backward analysis gives it to us out of the box. 713e8d8bef9SDimitry Andric BackwardDataflowWorklist Worklist(FunctionCFG, AC); 714e8d8bef9SDimitry Andric 715e8d8bef9SDimitry Andric // Let's visit EXIT. 716e8d8bef9SDimitry Andric const CFGBlock *Exit = &FunctionCFG.getExit(); 717e8d8bef9SDimitry Andric assignState(Exit, State(size(), ParameterStatus::NotCalled)); 718e8d8bef9SDimitry Andric Worklist.enqueuePredecessors(Exit); 719e8d8bef9SDimitry Andric 720e8d8bef9SDimitry Andric while (const CFGBlock *BB = Worklist.dequeue()) { 721e8d8bef9SDimitry Andric assert(BB && "Worklist should filter out null blocks"); 722e8d8bef9SDimitry Andric check(BB); 723e8d8bef9SDimitry Andric assert(CurrentState.isVisited() && 724e8d8bef9SDimitry Andric "After the check, basic block should be visited"); 725e8d8bef9SDimitry Andric 726e8d8bef9SDimitry Andric // Traverse successor basic blocks if the status of this block 727e8d8bef9SDimitry Andric // has changed. 728e8d8bef9SDimitry Andric if (assignState(BB, CurrentState)) { 729e8d8bef9SDimitry Andric Worklist.enqueuePredecessors(BB); 730e8d8bef9SDimitry Andric } 731e8d8bef9SDimitry Andric } 732e8d8bef9SDimitry Andric 733e8d8bef9SDimitry Andric // Check that we have all tracked parameters at the last block. 734e8d8bef9SDimitry Andric // As we are performing a backward version of the analysis, 735e8d8bef9SDimitry Andric // it should be the ENTRY block. 736e8d8bef9SDimitry Andric checkEntry(&FunctionCFG.getEntry()); 737e8d8bef9SDimitry Andric } 738e8d8bef9SDimitry Andric 739e8d8bef9SDimitry Andric void check(const CFGBlock *BB) { 740e8d8bef9SDimitry Andric // We start with a state 'inherited' from all the successors. 741e8d8bef9SDimitry Andric CurrentState = joinSuccessors(BB); 742e8d8bef9SDimitry Andric assert(CurrentState.isVisited() && 743e8d8bef9SDimitry Andric "Shouldn't start with a 'not visited' state"); 744e8d8bef9SDimitry Andric 745e8d8bef9SDimitry Andric // This is the 'exit' situation, broken promises are probably OK 746e8d8bef9SDimitry Andric // in such scenarios. 747e8d8bef9SDimitry Andric if (BB->hasNoReturnElement()) { 748e8d8bef9SDimitry Andric markNoReturn(); 749e8d8bef9SDimitry Andric // This block still can have calls (even multiple calls) and 750e8d8bef9SDimitry Andric // for this reason there is no early return here. 751e8d8bef9SDimitry Andric } 752e8d8bef9SDimitry Andric 753e8d8bef9SDimitry Andric // We use a backward dataflow propagation and for this reason we 754e8d8bef9SDimitry Andric // should traverse basic blocks bottom-up. 755e8d8bef9SDimitry Andric for (const CFGElement &Element : llvm::reverse(*BB)) { 756bdd1243dSDimitry Andric if (std::optional<CFGStmt> S = Element.getAs<CFGStmt>()) { 757e8d8bef9SDimitry Andric check(S->getStmt()); 758e8d8bef9SDimitry Andric } 759e8d8bef9SDimitry Andric } 760e8d8bef9SDimitry Andric } 761e8d8bef9SDimitry Andric void check(const Stmt *S) { Visit(S); } 762e8d8bef9SDimitry Andric 763e8d8bef9SDimitry Andric void checkEntry(const CFGBlock *Entry) { 764e8d8bef9SDimitry Andric // We finalize this algorithm with the ENTRY block because 765e8d8bef9SDimitry Andric // we use a backward version of the analysis. This is where 766e8d8bef9SDimitry Andric // we can judge that some of the tracked parameters are not called on 767e8d8bef9SDimitry Andric // every path from ENTRY to EXIT. 768e8d8bef9SDimitry Andric 769e8d8bef9SDimitry Andric const State &EntryStatus = getState(Entry); 770e8d8bef9SDimitry Andric llvm::BitVector NotCalledOnEveryPath(size(), false); 771e8d8bef9SDimitry Andric llvm::BitVector NotUsedOnEveryPath(size(), false); 772e8d8bef9SDimitry Andric 773e8d8bef9SDimitry Andric // Check if there are no calls of the marked parameter at all 774e8d8bef9SDimitry Andric for (const auto &IndexedStatus : llvm::enumerate(EntryStatus)) { 775e8d8bef9SDimitry Andric const ParmVarDecl *Parameter = getParameter(IndexedStatus.index()); 776e8d8bef9SDimitry Andric 777e8d8bef9SDimitry Andric switch (IndexedStatus.value().getKind()) { 778e8d8bef9SDimitry Andric case ParameterStatus::NotCalled: 779e8d8bef9SDimitry Andric // If there were places where this parameter escapes (aka being used), 780e8d8bef9SDimitry Andric // we can provide a more useful diagnostic by pointing at the exact 781e8d8bef9SDimitry Andric // branches where it is not even mentioned. 782e8d8bef9SDimitry Andric if (!hasEverEscaped(IndexedStatus.index())) { 783e8d8bef9SDimitry Andric // This parameter is was not used at all, so we should report the 784e8d8bef9SDimitry Andric // most generic version of the warning. 785e8d8bef9SDimitry Andric if (isCaptured(Parameter)) { 786e8d8bef9SDimitry Andric // We want to specify that it was captured by the block. 787e8d8bef9SDimitry Andric Handler.handleCapturedNeverCalled(Parameter, AC.getDecl(), 788e8d8bef9SDimitry Andric !isExplicitlyMarked(Parameter)); 789e8d8bef9SDimitry Andric } else { 790e8d8bef9SDimitry Andric Handler.handleNeverCalled(Parameter, 791e8d8bef9SDimitry Andric !isExplicitlyMarked(Parameter)); 792e8d8bef9SDimitry Andric } 793e8d8bef9SDimitry Andric } else { 794e8d8bef9SDimitry Andric // Mark it as 'interesting' to figure out which paths don't even 795e8d8bef9SDimitry Andric // have escapes. 796e8d8bef9SDimitry Andric NotUsedOnEveryPath[IndexedStatus.index()] = true; 797e8d8bef9SDimitry Andric } 798e8d8bef9SDimitry Andric 799e8d8bef9SDimitry Andric break; 800e8d8bef9SDimitry Andric case ParameterStatus::MaybeCalled: 801e8d8bef9SDimitry Andric // If we have 'maybe called' at this point, we have an error 802e8d8bef9SDimitry Andric // that there is at least one path where this parameter 803e8d8bef9SDimitry Andric // is not called. 804e8d8bef9SDimitry Andric // 805e8d8bef9SDimitry Andric // However, reporting the warning with only that information can be 806e8d8bef9SDimitry Andric // too vague for the users. For this reason, we mark such parameters 807e8d8bef9SDimitry Andric // as "interesting" for further analysis. 808e8d8bef9SDimitry Andric NotCalledOnEveryPath[IndexedStatus.index()] = true; 809e8d8bef9SDimitry Andric break; 810e8d8bef9SDimitry Andric default: 811e8d8bef9SDimitry Andric break; 812e8d8bef9SDimitry Andric } 813e8d8bef9SDimitry Andric } 814e8d8bef9SDimitry Andric 815fe6060f1SDimitry Andric // Early exit if we don't have parameters for extra analysis... 816fe6060f1SDimitry Andric if (NotCalledOnEveryPath.none() && NotUsedOnEveryPath.none() && 817fe6060f1SDimitry Andric // ... or if we've seen variables with cleanup functions. 818fe6060f1SDimitry Andric // We can't reason that we've seen every path in this case, 819fe6060f1SDimitry Andric // and thus abandon reporting any warnings that imply that. 820fe6060f1SDimitry Andric !FunctionHasCleanupVars) 821e8d8bef9SDimitry Andric return; 822e8d8bef9SDimitry Andric 823e8d8bef9SDimitry Andric // We are looking for a pair of blocks A, B so that the following is true: 824e8d8bef9SDimitry Andric // * A is a predecessor of B 825e8d8bef9SDimitry Andric // * B is marked as NotCalled 826e8d8bef9SDimitry Andric // * A has at least one successor marked as either 827e8d8bef9SDimitry Andric // Escaped or DefinitelyCalled 828e8d8bef9SDimitry Andric // 829e8d8bef9SDimitry Andric // In that situation, it is guaranteed that B is the first block of the path 830e8d8bef9SDimitry Andric // where the user doesn't call or use parameter in question. 831e8d8bef9SDimitry Andric // 832e8d8bef9SDimitry Andric // For this reason, branch A -> B can be used for reporting. 833e8d8bef9SDimitry Andric // 834e8d8bef9SDimitry Andric // This part of the algorithm is guarded by a condition that the function 835e8d8bef9SDimitry Andric // does indeed have a violation of contract. For this reason, we can 836e8d8bef9SDimitry Andric // spend more time to find a good spot to place the warning. 837e8d8bef9SDimitry Andric // 838e8d8bef9SDimitry Andric // The following algorithm has the worst case complexity of O(V + E), 839e8d8bef9SDimitry Andric // where V is the number of basic blocks in FunctionCFG, 840e8d8bef9SDimitry Andric // E is the number of edges between blocks in FunctionCFG. 841e8d8bef9SDimitry Andric for (const CFGBlock *BB : FunctionCFG) { 842e8d8bef9SDimitry Andric if (!BB) 843e8d8bef9SDimitry Andric continue; 844e8d8bef9SDimitry Andric 845e8d8bef9SDimitry Andric const State &BlockState = getState(BB); 846e8d8bef9SDimitry Andric 847e8d8bef9SDimitry Andric for (unsigned Index : llvm::seq(0u, size())) { 848e8d8bef9SDimitry Andric // We don't want to use 'isLosingCall' here because we want to report 849e8d8bef9SDimitry Andric // the following situation as well: 850e8d8bef9SDimitry Andric // 851e8d8bef9SDimitry Andric // MaybeCalled 852e8d8bef9SDimitry Andric // | ... | 853e8d8bef9SDimitry Andric // MaybeCalled NotCalled 854e8d8bef9SDimitry Andric // 855e8d8bef9SDimitry Andric // Even though successor is not 'DefinitelyCalled', it is still useful 856e8d8bef9SDimitry Andric // to report it, it is still a path without a call. 857e8d8bef9SDimitry Andric if (NotCalledOnEveryPath[Index] && 858e8d8bef9SDimitry Andric BlockState.getKindFor(Index) == ParameterStatus::MaybeCalled) { 859e8d8bef9SDimitry Andric 860e8d8bef9SDimitry Andric findAndReportNotCalledBranches(BB, Index); 861e8d8bef9SDimitry Andric } else if (NotUsedOnEveryPath[Index] && 862e8d8bef9SDimitry Andric isLosingEscape(BlockState, BB, Index)) { 863e8d8bef9SDimitry Andric 864e8d8bef9SDimitry Andric findAndReportNotCalledBranches(BB, Index, /* IsEscape = */ true); 865e8d8bef9SDimitry Andric } 866e8d8bef9SDimitry Andric } 867e8d8bef9SDimitry Andric } 868e8d8bef9SDimitry Andric } 869e8d8bef9SDimitry Andric 870e8d8bef9SDimitry Andric /// Check potential call of a tracked parameter. 871e8d8bef9SDimitry Andric void checkDirectCall(const CallExpr *Call) { 872e8d8bef9SDimitry Andric if (auto Index = getIndexOfCallee(Call)) { 873e8d8bef9SDimitry Andric processCallFor(*Index, Call); 874e8d8bef9SDimitry Andric } 875e8d8bef9SDimitry Andric } 876e8d8bef9SDimitry Andric 877e8d8bef9SDimitry Andric /// Check the call expression for being an indirect call of one of the tracked 878e8d8bef9SDimitry Andric /// parameters. It is indirect in the sense that this particular call is not 879e8d8bef9SDimitry Andric /// calling the parameter itself, but rather uses it as the argument. 880e8d8bef9SDimitry Andric template <class CallLikeExpr> 881e8d8bef9SDimitry Andric void checkIndirectCall(const CallLikeExpr *CallOrMessage) { 882e8d8bef9SDimitry Andric // CallExpr::arguments does not interact nicely with llvm::enumerate. 883bdd1243dSDimitry Andric llvm::ArrayRef<const Expr *> Arguments = 884bdd1243dSDimitry Andric llvm::ArrayRef(CallOrMessage->getArgs(), CallOrMessage->getNumArgs()); 885e8d8bef9SDimitry Andric 886e8d8bef9SDimitry Andric // Let's check if any of the call arguments is a point of interest. 887e8d8bef9SDimitry Andric for (const auto &Argument : llvm::enumerate(Arguments)) { 888e8d8bef9SDimitry Andric if (auto Index = getIndexOfExpression(Argument.value())) { 889e8d8bef9SDimitry Andric if (shouldBeCalledOnce(CallOrMessage, Argument.index())) { 890e8d8bef9SDimitry Andric // If the corresponding parameter is marked as 'called_once' we should 891e8d8bef9SDimitry Andric // consider it as a call. 892e8d8bef9SDimitry Andric processCallFor(*Index, CallOrMessage); 893fe6060f1SDimitry Andric } else { 894e8d8bef9SDimitry Andric // Otherwise, we mark this parameter as escaped, which can be 895e8d8bef9SDimitry Andric // interpreted both as called or not called depending on the context. 896fe6060f1SDimitry Andric processEscapeFor(*Index); 897e8d8bef9SDimitry Andric } 898e8d8bef9SDimitry Andric // Otherwise, let's keep the state as it is. 899e8d8bef9SDimitry Andric } 900e8d8bef9SDimitry Andric } 901e8d8bef9SDimitry Andric } 902e8d8bef9SDimitry Andric 903e8d8bef9SDimitry Andric /// Process call of the parameter with the given index 904e8d8bef9SDimitry Andric void processCallFor(unsigned Index, const Expr *Call) { 905e8d8bef9SDimitry Andric ParameterStatus &CurrentParamStatus = CurrentState.getStatusFor(Index); 906e8d8bef9SDimitry Andric 907e8d8bef9SDimitry Andric if (CurrentParamStatus.seenAnyCalls()) { 908e8d8bef9SDimitry Andric 909e8d8bef9SDimitry Andric // At this point, this parameter was called, so this is a second call. 910e8d8bef9SDimitry Andric const ParmVarDecl *Parameter = getParameter(Index); 911e8d8bef9SDimitry Andric Handler.handleDoubleCall( 912e8d8bef9SDimitry Andric Parameter, &CurrentState.getCallFor(Index), Call, 913e8d8bef9SDimitry Andric !isExplicitlyMarked(Parameter), 914e8d8bef9SDimitry Andric // We are sure that the second call is definitely 915e8d8bef9SDimitry Andric // going to happen if the status is 'DefinitelyCalled'. 916e8d8bef9SDimitry Andric CurrentParamStatus.getKind() == ParameterStatus::DefinitelyCalled); 917e8d8bef9SDimitry Andric 918e8d8bef9SDimitry Andric // Mark this parameter as already reported on, so we don't repeat 919e8d8bef9SDimitry Andric // warnings. 920e8d8bef9SDimitry Andric CurrentParamStatus = ParameterStatus::Reported; 921e8d8bef9SDimitry Andric 922e8d8bef9SDimitry Andric } else if (CurrentParamStatus.getKind() != ParameterStatus::Reported) { 923e8d8bef9SDimitry Andric // If we didn't report anything yet, let's mark this parameter 924e8d8bef9SDimitry Andric // as called. 925e8d8bef9SDimitry Andric ParameterStatus Called(ParameterStatus::DefinitelyCalled, Call); 926e8d8bef9SDimitry Andric CurrentParamStatus = Called; 927e8d8bef9SDimitry Andric } 928e8d8bef9SDimitry Andric } 929e8d8bef9SDimitry Andric 930fe6060f1SDimitry Andric /// Process escape of the parameter with the given index 931fe6060f1SDimitry Andric void processEscapeFor(unsigned Index) { 932fe6060f1SDimitry Andric ParameterStatus &CurrentParamStatus = CurrentState.getStatusFor(Index); 933fe6060f1SDimitry Andric 934fe6060f1SDimitry Andric // Escape overrides whatever error we think happened. 935*0fca6ea1SDimitry Andric if (CurrentParamStatus.isErrorStatus() && 936*0fca6ea1SDimitry Andric CurrentParamStatus.getKind() != ParameterStatus::Kind::Reported) { 937fe6060f1SDimitry Andric CurrentParamStatus = ParameterStatus::Escaped; 938fe6060f1SDimitry Andric } 939fe6060f1SDimitry Andric } 940fe6060f1SDimitry Andric 941e8d8bef9SDimitry Andric void findAndReportNotCalledBranches(const CFGBlock *Parent, unsigned Index, 942e8d8bef9SDimitry Andric bool IsEscape = false) { 943e8d8bef9SDimitry Andric for (const CFGBlock *Succ : Parent->succs()) { 944e8d8bef9SDimitry Andric if (!Succ) 945e8d8bef9SDimitry Andric continue; 946e8d8bef9SDimitry Andric 947e8d8bef9SDimitry Andric if (getState(Succ).getKindFor(Index) == ParameterStatus::NotCalled) { 948e8d8bef9SDimitry Andric assert(Parent->succ_size() >= 2 && 949e8d8bef9SDimitry Andric "Block should have at least two successors at this point"); 950e8d8bef9SDimitry Andric if (auto Clarification = NotCalledClarifier::clarify(Parent, Succ)) { 951e8d8bef9SDimitry Andric const ParmVarDecl *Parameter = getParameter(Index); 952fe6060f1SDimitry Andric Handler.handleNeverCalled( 953fe6060f1SDimitry Andric Parameter, AC.getDecl(), Clarification->Location, 954fe6060f1SDimitry Andric Clarification->Reason, !IsEscape, !isExplicitlyMarked(Parameter)); 955e8d8bef9SDimitry Andric } 956e8d8bef9SDimitry Andric } 957e8d8bef9SDimitry Andric } 958e8d8bef9SDimitry Andric } 959e8d8bef9SDimitry Andric 960e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 961e8d8bef9SDimitry Andric // Predicate functions to check parameters 962e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 963e8d8bef9SDimitry Andric 964e8d8bef9SDimitry Andric /// Return true if parameter is explicitly marked as 'called_once'. 965e8d8bef9SDimitry Andric static bool isExplicitlyMarked(const ParmVarDecl *Parameter) { 966e8d8bef9SDimitry Andric return Parameter->hasAttr<CalledOnceAttr>(); 967e8d8bef9SDimitry Andric } 968e8d8bef9SDimitry Andric 969e8d8bef9SDimitry Andric /// Return true if the given name matches conventional pattens. 970e8d8bef9SDimitry Andric static bool isConventional(llvm::StringRef Name) { 971e8d8bef9SDimitry Andric return llvm::count(CONVENTIONAL_NAMES, Name) != 0; 972e8d8bef9SDimitry Andric } 973e8d8bef9SDimitry Andric 974e8d8bef9SDimitry Andric /// Return true if the given name has conventional suffixes. 975e8d8bef9SDimitry Andric static bool hasConventionalSuffix(llvm::StringRef Name) { 976e8d8bef9SDimitry Andric return llvm::any_of(CONVENTIONAL_SUFFIXES, [Name](llvm::StringRef Suffix) { 9775f757f3fSDimitry Andric return Name.ends_with(Suffix); 978e8d8bef9SDimitry Andric }); 979e8d8bef9SDimitry Andric } 980e8d8bef9SDimitry Andric 981e8d8bef9SDimitry Andric /// Return true if the given type can be used for conventional parameters. 982e8d8bef9SDimitry Andric static bool isConventional(QualType Ty) { 983e8d8bef9SDimitry Andric if (!Ty->isBlockPointerType()) { 984e8d8bef9SDimitry Andric return false; 985e8d8bef9SDimitry Andric } 986e8d8bef9SDimitry Andric 987fe6060f1SDimitry Andric QualType BlockType = Ty->castAs<BlockPointerType>()->getPointeeType(); 988e8d8bef9SDimitry Andric // Completion handlers should have a block type with void return type. 989fe6060f1SDimitry Andric return BlockType->castAs<FunctionType>()->getReturnType()->isVoidType(); 990e8d8bef9SDimitry Andric } 991e8d8bef9SDimitry Andric 992e8d8bef9SDimitry Andric /// Return true if the only parameter of the function is conventional. 993e8d8bef9SDimitry Andric static bool isOnlyParameterConventional(const FunctionDecl *Function) { 994e8d8bef9SDimitry Andric IdentifierInfo *II = Function->getIdentifier(); 995e8d8bef9SDimitry Andric return Function->getNumParams() == 1 && II && 996e8d8bef9SDimitry Andric hasConventionalSuffix(II->getName()); 997e8d8bef9SDimitry Andric } 998e8d8bef9SDimitry Andric 999e8d8bef9SDimitry Andric /// Return true/false if 'swift_async' attribute states that the given 1000e8d8bef9SDimitry Andric /// parameter is conventionally called once. 1001bdd1243dSDimitry Andric /// Return std::nullopt if the given declaration doesn't have 'swift_async' 1002e8d8bef9SDimitry Andric /// attribute. 1003bdd1243dSDimitry Andric static std::optional<bool> isConventionalSwiftAsync(const Decl *D, 1004e8d8bef9SDimitry Andric unsigned ParamIndex) { 1005e8d8bef9SDimitry Andric if (const SwiftAsyncAttr *A = D->getAttr<SwiftAsyncAttr>()) { 1006e8d8bef9SDimitry Andric if (A->getKind() == SwiftAsyncAttr::None) { 1007e8d8bef9SDimitry Andric return false; 1008e8d8bef9SDimitry Andric } 1009e8d8bef9SDimitry Andric 1010e8d8bef9SDimitry Andric return A->getCompletionHandlerIndex().getASTIndex() == ParamIndex; 1011e8d8bef9SDimitry Andric } 1012bdd1243dSDimitry Andric return std::nullopt; 1013e8d8bef9SDimitry Andric } 1014e8d8bef9SDimitry Andric 1015fe6060f1SDimitry Andric /// Return true if the specified selector represents init method. 1016fe6060f1SDimitry Andric static bool isInitMethod(Selector MethodSelector) { 1017fe6060f1SDimitry Andric return MethodSelector.getMethodFamily() == OMF_init; 1018fe6060f1SDimitry Andric } 1019fe6060f1SDimitry Andric 1020e8d8bef9SDimitry Andric /// Return true if the specified selector piece matches conventions. 1021e8d8bef9SDimitry Andric static bool isConventionalSelectorPiece(Selector MethodSelector, 1022e8d8bef9SDimitry Andric unsigned PieceIndex, 1023e8d8bef9SDimitry Andric QualType PieceType) { 1024fe6060f1SDimitry Andric if (!isConventional(PieceType) || isInitMethod(MethodSelector)) { 1025e8d8bef9SDimitry Andric return false; 1026e8d8bef9SDimitry Andric } 1027e8d8bef9SDimitry Andric 1028e8d8bef9SDimitry Andric if (MethodSelector.getNumArgs() == 1) { 1029e8d8bef9SDimitry Andric assert(PieceIndex == 0); 1030e8d8bef9SDimitry Andric return hasConventionalSuffix(MethodSelector.getNameForSlot(0)); 1031e8d8bef9SDimitry Andric } 1032e8d8bef9SDimitry Andric 1033fe6060f1SDimitry Andric llvm::StringRef PieceName = MethodSelector.getNameForSlot(PieceIndex); 1034fe6060f1SDimitry Andric return isConventional(PieceName) || hasConventionalSuffix(PieceName); 1035e8d8bef9SDimitry Andric } 1036e8d8bef9SDimitry Andric 1037e8d8bef9SDimitry Andric bool shouldBeCalledOnce(const ParmVarDecl *Parameter) const { 1038e8d8bef9SDimitry Andric return isExplicitlyMarked(Parameter) || 1039e8d8bef9SDimitry Andric (CheckConventionalParameters && 1040fe6060f1SDimitry Andric (isConventional(Parameter->getName()) || 1041fe6060f1SDimitry Andric hasConventionalSuffix(Parameter->getName())) && 1042e8d8bef9SDimitry Andric isConventional(Parameter->getType())); 1043e8d8bef9SDimitry Andric } 1044e8d8bef9SDimitry Andric 1045e8d8bef9SDimitry Andric bool shouldBeCalledOnce(const DeclContext *ParamContext, 1046e8d8bef9SDimitry Andric const ParmVarDecl *Param) { 1047e8d8bef9SDimitry Andric unsigned ParamIndex = Param->getFunctionScopeIndex(); 1048e8d8bef9SDimitry Andric if (const auto *Function = dyn_cast<FunctionDecl>(ParamContext)) { 1049e8d8bef9SDimitry Andric return shouldBeCalledOnce(Function, ParamIndex); 1050e8d8bef9SDimitry Andric } 1051e8d8bef9SDimitry Andric if (const auto *Method = dyn_cast<ObjCMethodDecl>(ParamContext)) { 1052e8d8bef9SDimitry Andric return shouldBeCalledOnce(Method, ParamIndex); 1053e8d8bef9SDimitry Andric } 1054e8d8bef9SDimitry Andric return shouldBeCalledOnce(Param); 1055e8d8bef9SDimitry Andric } 1056e8d8bef9SDimitry Andric 1057e8d8bef9SDimitry Andric bool shouldBeCalledOnce(const BlockDecl *Block, unsigned ParamIndex) const { 1058e8d8bef9SDimitry Andric return shouldBeCalledOnce(Block->getParamDecl(ParamIndex)); 1059e8d8bef9SDimitry Andric } 1060e8d8bef9SDimitry Andric 1061e8d8bef9SDimitry Andric bool shouldBeCalledOnce(const FunctionDecl *Function, 1062e8d8bef9SDimitry Andric unsigned ParamIndex) const { 1063e8d8bef9SDimitry Andric if (ParamIndex >= Function->getNumParams()) { 1064e8d8bef9SDimitry Andric return false; 1065e8d8bef9SDimitry Andric } 1066e8d8bef9SDimitry Andric // 'swift_async' goes first and overrides anything else. 1067e8d8bef9SDimitry Andric if (auto ConventionalAsync = 1068e8d8bef9SDimitry Andric isConventionalSwiftAsync(Function, ParamIndex)) { 106981ad6265SDimitry Andric return *ConventionalAsync; 1070e8d8bef9SDimitry Andric } 1071e8d8bef9SDimitry Andric 1072e8d8bef9SDimitry Andric return shouldBeCalledOnce(Function->getParamDecl(ParamIndex)) || 1073e8d8bef9SDimitry Andric (CheckConventionalParameters && 1074e8d8bef9SDimitry Andric isOnlyParameterConventional(Function)); 1075e8d8bef9SDimitry Andric } 1076e8d8bef9SDimitry Andric 1077e8d8bef9SDimitry Andric bool shouldBeCalledOnce(const ObjCMethodDecl *Method, 1078e8d8bef9SDimitry Andric unsigned ParamIndex) const { 1079e8d8bef9SDimitry Andric Selector MethodSelector = Method->getSelector(); 1080e8d8bef9SDimitry Andric if (ParamIndex >= MethodSelector.getNumArgs()) { 1081e8d8bef9SDimitry Andric return false; 1082e8d8bef9SDimitry Andric } 1083e8d8bef9SDimitry Andric 1084e8d8bef9SDimitry Andric // 'swift_async' goes first and overrides anything else. 1085e8d8bef9SDimitry Andric if (auto ConventionalAsync = isConventionalSwiftAsync(Method, ParamIndex)) { 108681ad6265SDimitry Andric return *ConventionalAsync; 1087e8d8bef9SDimitry Andric } 1088e8d8bef9SDimitry Andric 1089e8d8bef9SDimitry Andric const ParmVarDecl *Parameter = Method->getParamDecl(ParamIndex); 1090e8d8bef9SDimitry Andric return shouldBeCalledOnce(Parameter) || 1091e8d8bef9SDimitry Andric (CheckConventionalParameters && 1092e8d8bef9SDimitry Andric isConventionalSelectorPiece(MethodSelector, ParamIndex, 1093e8d8bef9SDimitry Andric Parameter->getType())); 1094e8d8bef9SDimitry Andric } 1095e8d8bef9SDimitry Andric 1096e8d8bef9SDimitry Andric bool shouldBeCalledOnce(const CallExpr *Call, unsigned ParamIndex) const { 1097e8d8bef9SDimitry Andric const FunctionDecl *Function = Call->getDirectCallee(); 1098e8d8bef9SDimitry Andric return Function && shouldBeCalledOnce(Function, ParamIndex); 1099e8d8bef9SDimitry Andric } 1100e8d8bef9SDimitry Andric 1101e8d8bef9SDimitry Andric bool shouldBeCalledOnce(const ObjCMessageExpr *Message, 1102e8d8bef9SDimitry Andric unsigned ParamIndex) const { 1103e8d8bef9SDimitry Andric const ObjCMethodDecl *Method = Message->getMethodDecl(); 1104e8d8bef9SDimitry Andric return Method && ParamIndex < Method->param_size() && 1105e8d8bef9SDimitry Andric shouldBeCalledOnce(Method, ParamIndex); 1106e8d8bef9SDimitry Andric } 1107e8d8bef9SDimitry Andric 1108e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 1109e8d8bef9SDimitry Andric // Utility methods 1110e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 1111e8d8bef9SDimitry Andric 1112e8d8bef9SDimitry Andric bool isCaptured(const ParmVarDecl *Parameter) const { 1113e8d8bef9SDimitry Andric if (const BlockDecl *Block = dyn_cast<BlockDecl>(AC.getDecl())) { 1114e8d8bef9SDimitry Andric return Block->capturesVariable(Parameter); 1115e8d8bef9SDimitry Andric } 1116e8d8bef9SDimitry Andric return false; 1117e8d8bef9SDimitry Andric } 1118e8d8bef9SDimitry Andric 1119fe6060f1SDimitry Andric // Return a call site where the block is called exactly once or null otherwise 1120fe6060f1SDimitry Andric const Expr *getBlockGuaraneedCallSite(const BlockExpr *Block) const { 1121fe6060f1SDimitry Andric ParentMap &PM = AC.getParentMap(); 1122fe6060f1SDimitry Andric 1123fe6060f1SDimitry Andric // We don't want to track the block through assignments and so on, instead 1124fe6060f1SDimitry Andric // we simply see how the block used and if it's used directly in a call, 1125fe6060f1SDimitry Andric // we decide based on call to what it is. 1126fe6060f1SDimitry Andric // 1127fe6060f1SDimitry Andric // In order to do this, we go up the parents of the block looking for 1128fe6060f1SDimitry Andric // a call or a message expressions. These might not be immediate parents 1129fe6060f1SDimitry Andric // of the actual block expression due to casts and parens, so we skip them. 1130fe6060f1SDimitry Andric for (const Stmt *Prev = Block, *Current = PM.getParent(Block); 1131fe6060f1SDimitry Andric Current != nullptr; Prev = Current, Current = PM.getParent(Current)) { 1132fe6060f1SDimitry Andric // Skip no-op (for our case) operations. 1133fe6060f1SDimitry Andric if (isa<CastExpr>(Current) || isa<ParenExpr>(Current)) 1134fe6060f1SDimitry Andric continue; 1135fe6060f1SDimitry Andric 1136fe6060f1SDimitry Andric // At this point, Prev represents our block as an immediate child of the 1137fe6060f1SDimitry Andric // call. 1138fe6060f1SDimitry Andric if (const auto *Call = dyn_cast<CallExpr>(Current)) { 1139fe6060f1SDimitry Andric // It might be the call of the Block itself... 1140fe6060f1SDimitry Andric if (Call->getCallee() == Prev) 1141fe6060f1SDimitry Andric return Call; 1142fe6060f1SDimitry Andric 1143fe6060f1SDimitry Andric // ...or it can be an indirect call of the block. 1144fe6060f1SDimitry Andric return shouldBlockArgumentBeCalledOnce(Call, Prev) ? Call : nullptr; 1145fe6060f1SDimitry Andric } 1146fe6060f1SDimitry Andric if (const auto *Message = dyn_cast<ObjCMessageExpr>(Current)) { 1147fe6060f1SDimitry Andric return shouldBlockArgumentBeCalledOnce(Message, Prev) ? Message 1148fe6060f1SDimitry Andric : nullptr; 1149fe6060f1SDimitry Andric } 1150fe6060f1SDimitry Andric 1151fe6060f1SDimitry Andric break; 1152fe6060f1SDimitry Andric } 1153fe6060f1SDimitry Andric 1154fe6060f1SDimitry Andric return nullptr; 1155fe6060f1SDimitry Andric } 1156fe6060f1SDimitry Andric 1157fe6060f1SDimitry Andric template <class CallLikeExpr> 1158fe6060f1SDimitry Andric bool shouldBlockArgumentBeCalledOnce(const CallLikeExpr *CallOrMessage, 1159fe6060f1SDimitry Andric const Stmt *BlockArgument) const { 1160fe6060f1SDimitry Andric // CallExpr::arguments does not interact nicely with llvm::enumerate. 1161bdd1243dSDimitry Andric llvm::ArrayRef<const Expr *> Arguments = 1162bdd1243dSDimitry Andric llvm::ArrayRef(CallOrMessage->getArgs(), CallOrMessage->getNumArgs()); 1163fe6060f1SDimitry Andric 1164fe6060f1SDimitry Andric for (const auto &Argument : llvm::enumerate(Arguments)) { 1165fe6060f1SDimitry Andric if (Argument.value() == BlockArgument) { 1166fe6060f1SDimitry Andric return shouldBlockArgumentBeCalledOnce(CallOrMessage, Argument.index()); 1167fe6060f1SDimitry Andric } 1168fe6060f1SDimitry Andric } 1169fe6060f1SDimitry Andric 1170fe6060f1SDimitry Andric return false; 1171fe6060f1SDimitry Andric } 1172fe6060f1SDimitry Andric 1173fe6060f1SDimitry Andric bool shouldBlockArgumentBeCalledOnce(const CallExpr *Call, 1174fe6060f1SDimitry Andric unsigned ParamIndex) const { 1175fe6060f1SDimitry Andric const FunctionDecl *Function = Call->getDirectCallee(); 1176fe6060f1SDimitry Andric return shouldBlockArgumentBeCalledOnce(Function, ParamIndex) || 1177fe6060f1SDimitry Andric shouldBeCalledOnce(Call, ParamIndex); 1178fe6060f1SDimitry Andric } 1179fe6060f1SDimitry Andric 1180fe6060f1SDimitry Andric bool shouldBlockArgumentBeCalledOnce(const ObjCMessageExpr *Message, 1181fe6060f1SDimitry Andric unsigned ParamIndex) const { 1182fe6060f1SDimitry Andric // At the moment, we don't have any Obj-C methods we want to specifically 1183fe6060f1SDimitry Andric // check in here. 1184fe6060f1SDimitry Andric return shouldBeCalledOnce(Message, ParamIndex); 1185fe6060f1SDimitry Andric } 1186fe6060f1SDimitry Andric 1187fe6060f1SDimitry Andric static bool shouldBlockArgumentBeCalledOnce(const FunctionDecl *Function, 1188fe6060f1SDimitry Andric unsigned ParamIndex) { 1189fe6060f1SDimitry Andric // There is a list of important API functions that while not following 1190fe6060f1SDimitry Andric // conventions nor being directly annotated, still guarantee that the 1191fe6060f1SDimitry Andric // callback parameter will be called exactly once. 1192fe6060f1SDimitry Andric // 1193fe6060f1SDimitry Andric // Here we check if this is the case. 1194fe6060f1SDimitry Andric return Function && 1195fe6060f1SDimitry Andric llvm::any_of(KNOWN_CALLED_ONCE_PARAMETERS, 1196fe6060f1SDimitry Andric [Function, ParamIndex]( 1197fe6060f1SDimitry Andric const KnownCalledOnceParameter &Reference) { 1198fe6060f1SDimitry Andric return Reference.FunctionName == 1199fe6060f1SDimitry Andric Function->getName() && 1200fe6060f1SDimitry Andric Reference.ParamIndex == ParamIndex; 1201fe6060f1SDimitry Andric }); 1202fe6060f1SDimitry Andric } 1203fe6060f1SDimitry Andric 1204e8d8bef9SDimitry Andric /// Return true if the analyzed function is actually a default implementation 1205e8d8bef9SDimitry Andric /// of the method that has to be overriden. 1206e8d8bef9SDimitry Andric /// 1207e8d8bef9SDimitry Andric /// These functions can have tracked parameters, but wouldn't call them 1208e8d8bef9SDimitry Andric /// because they are not designed to perform any meaningful actions. 1209e8d8bef9SDimitry Andric /// 1210e8d8bef9SDimitry Andric /// There are a couple of flavors of such default implementations: 1211e8d8bef9SDimitry Andric /// 1. Empty methods or methods with a single return statement 1212e8d8bef9SDimitry Andric /// 2. Methods that have one block with a call to no return function 1213e8d8bef9SDimitry Andric /// 3. Methods with only assertion-like operations 1214e8d8bef9SDimitry Andric bool isPossiblyEmptyImpl() const { 1215e8d8bef9SDimitry Andric if (!isa<ObjCMethodDecl>(AC.getDecl())) { 1216e8d8bef9SDimitry Andric // We care only about functions that are not supposed to be called. 1217e8d8bef9SDimitry Andric // Only methods can be overriden. 1218e8d8bef9SDimitry Andric return false; 1219e8d8bef9SDimitry Andric } 1220e8d8bef9SDimitry Andric 1221e8d8bef9SDimitry Andric // Case #1 (without return statements) 1222e8d8bef9SDimitry Andric if (FunctionCFG.size() == 2) { 1223e8d8bef9SDimitry Andric // Method has only two blocks: ENTRY and EXIT. 1224e8d8bef9SDimitry Andric // This is equivalent to empty function. 1225e8d8bef9SDimitry Andric return true; 1226e8d8bef9SDimitry Andric } 1227e8d8bef9SDimitry Andric 1228e8d8bef9SDimitry Andric // Case #2 1229e8d8bef9SDimitry Andric if (FunctionCFG.size() == 3) { 1230e8d8bef9SDimitry Andric const CFGBlock &Entry = FunctionCFG.getEntry(); 1231e8d8bef9SDimitry Andric if (Entry.succ_empty()) { 1232e8d8bef9SDimitry Andric return false; 1233e8d8bef9SDimitry Andric } 1234e8d8bef9SDimitry Andric 1235e8d8bef9SDimitry Andric const CFGBlock *OnlyBlock = *Entry.succ_begin(); 1236e8d8bef9SDimitry Andric // Method has only one block, let's see if it has a no-return 1237e8d8bef9SDimitry Andric // element. 1238e8d8bef9SDimitry Andric if (OnlyBlock && OnlyBlock->hasNoReturnElement()) { 1239e8d8bef9SDimitry Andric return true; 1240e8d8bef9SDimitry Andric } 1241e8d8bef9SDimitry Andric // Fallthrough, CFGs with only one block can fall into #1 and #3 as well. 1242e8d8bef9SDimitry Andric } 1243e8d8bef9SDimitry Andric 1244e8d8bef9SDimitry Andric // Cases #1 (return statements) and #3. 1245e8d8bef9SDimitry Andric // 1246e8d8bef9SDimitry Andric // It is hard to detect that something is an assertion or came 1247e8d8bef9SDimitry Andric // from assertion. Here we use a simple heuristic: 1248e8d8bef9SDimitry Andric // 1249e8d8bef9SDimitry Andric // - If it came from a macro, it can be an assertion. 1250e8d8bef9SDimitry Andric // 1251e8d8bef9SDimitry Andric // Additionally, we can't assume a number of basic blocks or the CFG's 1252e8d8bef9SDimitry Andric // structure because assertions might include loops and conditions. 1253e8d8bef9SDimitry Andric return llvm::all_of(FunctionCFG, [](const CFGBlock *BB) { 1254e8d8bef9SDimitry Andric if (!BB) { 1255e8d8bef9SDimitry Andric // Unreachable blocks are totally fine. 1256e8d8bef9SDimitry Andric return true; 1257e8d8bef9SDimitry Andric } 1258e8d8bef9SDimitry Andric 1259e8d8bef9SDimitry Andric // Return statements can have sub-expressions that are represented as 1260e8d8bef9SDimitry Andric // separate statements of a basic block. We should allow this. 1261e8d8bef9SDimitry Andric // This parent map will be initialized with a parent tree for all 1262e8d8bef9SDimitry Andric // subexpressions of the block's return statement (if it has one). 1263e8d8bef9SDimitry Andric std::unique_ptr<ParentMap> ReturnChildren; 1264e8d8bef9SDimitry Andric 1265e8d8bef9SDimitry Andric return llvm::all_of( 1266e8d8bef9SDimitry Andric llvm::reverse(*BB), // we should start with return statements, if we 1267e8d8bef9SDimitry Andric // have any, i.e. from the bottom of the block 1268e8d8bef9SDimitry Andric [&ReturnChildren](const CFGElement &Element) { 1269bdd1243dSDimitry Andric if (std::optional<CFGStmt> S = Element.getAs<CFGStmt>()) { 1270e8d8bef9SDimitry Andric const Stmt *SuspiciousStmt = S->getStmt(); 1271e8d8bef9SDimitry Andric 1272e8d8bef9SDimitry Andric if (isa<ReturnStmt>(SuspiciousStmt)) { 1273e8d8bef9SDimitry Andric // Let's initialize this structure to test whether 1274e8d8bef9SDimitry Andric // some further statement is a part of this return. 1275e8d8bef9SDimitry Andric ReturnChildren = std::make_unique<ParentMap>( 1276e8d8bef9SDimitry Andric const_cast<Stmt *>(SuspiciousStmt)); 1277e8d8bef9SDimitry Andric // Return statements are allowed as part of #1. 1278e8d8bef9SDimitry Andric return true; 1279e8d8bef9SDimitry Andric } 1280e8d8bef9SDimitry Andric 1281e8d8bef9SDimitry Andric return SuspiciousStmt->getBeginLoc().isMacroID() || 1282e8d8bef9SDimitry Andric (ReturnChildren && 1283e8d8bef9SDimitry Andric ReturnChildren->hasParent(SuspiciousStmt)); 1284e8d8bef9SDimitry Andric } 1285e8d8bef9SDimitry Andric return true; 1286e8d8bef9SDimitry Andric }); 1287e8d8bef9SDimitry Andric }); 1288e8d8bef9SDimitry Andric } 1289e8d8bef9SDimitry Andric 1290e8d8bef9SDimitry Andric /// Check if parameter with the given index has ever escaped. 1291e8d8bef9SDimitry Andric bool hasEverEscaped(unsigned Index) const { 1292e8d8bef9SDimitry Andric return llvm::any_of(States, [Index](const State &StateForOneBB) { 1293e8d8bef9SDimitry Andric return StateForOneBB.getKindFor(Index) == ParameterStatus::Escaped; 1294e8d8bef9SDimitry Andric }); 1295e8d8bef9SDimitry Andric } 1296e8d8bef9SDimitry Andric 1297e8d8bef9SDimitry Andric /// Return status stored for the given basic block. 1298e8d8bef9SDimitry Andric /// \{ 1299e8d8bef9SDimitry Andric State &getState(const CFGBlock *BB) { 1300e8d8bef9SDimitry Andric assert(BB); 1301e8d8bef9SDimitry Andric return States[BB->getBlockID()]; 1302e8d8bef9SDimitry Andric } 1303e8d8bef9SDimitry Andric const State &getState(const CFGBlock *BB) const { 1304e8d8bef9SDimitry Andric assert(BB); 1305e8d8bef9SDimitry Andric return States[BB->getBlockID()]; 1306e8d8bef9SDimitry Andric } 1307e8d8bef9SDimitry Andric /// \} 1308e8d8bef9SDimitry Andric 1309e8d8bef9SDimitry Andric /// Assign status to the given basic block. 1310e8d8bef9SDimitry Andric /// 1311e8d8bef9SDimitry Andric /// Returns true when the stored status changed. 1312e8d8bef9SDimitry Andric bool assignState(const CFGBlock *BB, const State &ToAssign) { 1313e8d8bef9SDimitry Andric State &Current = getState(BB); 1314e8d8bef9SDimitry Andric if (Current == ToAssign) { 1315e8d8bef9SDimitry Andric return false; 1316e8d8bef9SDimitry Andric } 1317e8d8bef9SDimitry Andric 1318e8d8bef9SDimitry Andric Current = ToAssign; 1319e8d8bef9SDimitry Andric return true; 1320e8d8bef9SDimitry Andric } 1321e8d8bef9SDimitry Andric 1322e8d8bef9SDimitry Andric /// Join all incoming statuses for the given basic block. 1323e8d8bef9SDimitry Andric State joinSuccessors(const CFGBlock *BB) const { 1324e8d8bef9SDimitry Andric auto Succs = 1325e8d8bef9SDimitry Andric llvm::make_filter_range(BB->succs(), [this](const CFGBlock *Succ) { 1326e8d8bef9SDimitry Andric return Succ && this->getState(Succ).isVisited(); 1327e8d8bef9SDimitry Andric }); 1328e8d8bef9SDimitry Andric // We came to this block from somewhere after all. 1329e8d8bef9SDimitry Andric assert(!Succs.empty() && 1330e8d8bef9SDimitry Andric "Basic block should have at least one visited successor"); 1331e8d8bef9SDimitry Andric 1332e8d8bef9SDimitry Andric State Result = getState(*Succs.begin()); 1333e8d8bef9SDimitry Andric 1334e8d8bef9SDimitry Andric for (const CFGBlock *Succ : llvm::drop_begin(Succs, 1)) { 1335e8d8bef9SDimitry Andric Result.join(getState(Succ)); 1336e8d8bef9SDimitry Andric } 1337e8d8bef9SDimitry Andric 1338e8d8bef9SDimitry Andric if (const Expr *Condition = getCondition(BB->getTerminatorStmt())) { 1339e8d8bef9SDimitry Andric handleConditional(BB, Condition, Result); 1340e8d8bef9SDimitry Andric } 1341e8d8bef9SDimitry Andric 1342e8d8bef9SDimitry Andric return Result; 1343e8d8bef9SDimitry Andric } 1344e8d8bef9SDimitry Andric 1345e8d8bef9SDimitry Andric void handleConditional(const CFGBlock *BB, const Expr *Condition, 1346e8d8bef9SDimitry Andric State &ToAlter) const { 1347e8d8bef9SDimitry Andric handleParameterCheck(BB, Condition, ToAlter); 1348e8d8bef9SDimitry Andric if (SuppressOnConventionalErrorPaths) { 1349e8d8bef9SDimitry Andric handleConventionalCheck(BB, Condition, ToAlter); 1350e8d8bef9SDimitry Andric } 1351e8d8bef9SDimitry Andric } 1352e8d8bef9SDimitry Andric 1353e8d8bef9SDimitry Andric void handleParameterCheck(const CFGBlock *BB, const Expr *Condition, 1354e8d8bef9SDimitry Andric State &ToAlter) const { 1355e8d8bef9SDimitry Andric // In this function, we try to deal with the following pattern: 1356e8d8bef9SDimitry Andric // 1357e8d8bef9SDimitry Andric // if (parameter) 1358e8d8bef9SDimitry Andric // parameter(...); 1359e8d8bef9SDimitry Andric // 1360e8d8bef9SDimitry Andric // It's not good to show a warning here because clearly 'parameter' 1361e8d8bef9SDimitry Andric // couldn't and shouldn't be called on the 'else' path. 1362e8d8bef9SDimitry Andric // 1363e8d8bef9SDimitry Andric // Let's check if this if statement has a check involving one of 1364e8d8bef9SDimitry Andric // the tracked parameters. 1365e8d8bef9SDimitry Andric if (const ParmVarDecl *Parameter = findReferencedParmVarDecl( 1366e8d8bef9SDimitry Andric Condition, 1367e8d8bef9SDimitry Andric /* ShouldRetrieveFromComparisons = */ true)) { 1368e8d8bef9SDimitry Andric if (const auto Index = getIndex(*Parameter)) { 1369e8d8bef9SDimitry Andric ParameterStatus &CurrentStatus = ToAlter.getStatusFor(*Index); 1370e8d8bef9SDimitry Andric 1371e8d8bef9SDimitry Andric // We don't want to deep dive into semantics of the check and 1372e8d8bef9SDimitry Andric // figure out if that check was for null or something else. 1373e8d8bef9SDimitry Andric // We simply trust the user that they know what they are doing. 1374e8d8bef9SDimitry Andric // 1375e8d8bef9SDimitry Andric // For this reason, in the following loop we look for the 1376e8d8bef9SDimitry Andric // best-looking option. 1377e8d8bef9SDimitry Andric for (const CFGBlock *Succ : BB->succs()) { 1378e8d8bef9SDimitry Andric if (!Succ) 1379e8d8bef9SDimitry Andric continue; 1380e8d8bef9SDimitry Andric 1381e8d8bef9SDimitry Andric const ParameterStatus &StatusInSucc = 1382e8d8bef9SDimitry Andric getState(Succ).getStatusFor(*Index); 1383e8d8bef9SDimitry Andric 1384e8d8bef9SDimitry Andric if (StatusInSucc.isErrorStatus()) { 1385e8d8bef9SDimitry Andric continue; 1386e8d8bef9SDimitry Andric } 1387e8d8bef9SDimitry Andric 1388e8d8bef9SDimitry Andric // Let's use this status instead. 1389e8d8bef9SDimitry Andric CurrentStatus = StatusInSucc; 1390e8d8bef9SDimitry Andric 1391e8d8bef9SDimitry Andric if (StatusInSucc.getKind() == ParameterStatus::DefinitelyCalled) { 1392e8d8bef9SDimitry Andric // This is the best option to have and we already found it. 1393e8d8bef9SDimitry Andric break; 1394e8d8bef9SDimitry Andric } 1395e8d8bef9SDimitry Andric 1396e8d8bef9SDimitry Andric // If we found 'Escaped' first, we still might find 'DefinitelyCalled' 1397e8d8bef9SDimitry Andric // on the other branch. And we prefer the latter. 1398e8d8bef9SDimitry Andric } 1399e8d8bef9SDimitry Andric } 1400e8d8bef9SDimitry Andric } 1401e8d8bef9SDimitry Andric } 1402e8d8bef9SDimitry Andric 1403e8d8bef9SDimitry Andric void handleConventionalCheck(const CFGBlock *BB, const Expr *Condition, 1404e8d8bef9SDimitry Andric State &ToAlter) const { 1405e8d8bef9SDimitry Andric // Even when the analysis is technically correct, it is a widespread pattern 1406e8d8bef9SDimitry Andric // not to call completion handlers in some scenarios. These usually have 1407e8d8bef9SDimitry Andric // typical conditional names, such as 'error' or 'cancel'. 1408e8d8bef9SDimitry Andric if (!mentionsAnyOfConventionalNames(Condition)) { 1409e8d8bef9SDimitry Andric return; 1410e8d8bef9SDimitry Andric } 1411e8d8bef9SDimitry Andric 1412e8d8bef9SDimitry Andric for (const auto &IndexedStatus : llvm::enumerate(ToAlter)) { 1413e8d8bef9SDimitry Andric const ParmVarDecl *Parameter = getParameter(IndexedStatus.index()); 1414e8d8bef9SDimitry Andric // Conventions do not apply to explicitly marked parameters. 1415e8d8bef9SDimitry Andric if (isExplicitlyMarked(Parameter)) { 1416e8d8bef9SDimitry Andric continue; 1417e8d8bef9SDimitry Andric } 1418e8d8bef9SDimitry Andric 1419e8d8bef9SDimitry Andric ParameterStatus &CurrentStatus = IndexedStatus.value(); 1420e8d8bef9SDimitry Andric // If we did find that on one of the branches the user uses the callback 1421e8d8bef9SDimitry Andric // and doesn't on the other path, we believe that they know what they are 1422e8d8bef9SDimitry Andric // doing and trust them. 1423e8d8bef9SDimitry Andric // 1424e8d8bef9SDimitry Andric // There are two possible scenarios for that: 1425e8d8bef9SDimitry Andric // 1. Current status is 'MaybeCalled' and one of the branches is 1426e8d8bef9SDimitry Andric // 'DefinitelyCalled' 1427e8d8bef9SDimitry Andric // 2. Current status is 'NotCalled' and one of the branches is 'Escaped' 1428e8d8bef9SDimitry Andric if (isLosingCall(ToAlter, BB, IndexedStatus.index()) || 1429e8d8bef9SDimitry Andric isLosingEscape(ToAlter, BB, IndexedStatus.index())) { 1430e8d8bef9SDimitry Andric CurrentStatus = ParameterStatus::Escaped; 1431e8d8bef9SDimitry Andric } 1432e8d8bef9SDimitry Andric } 1433e8d8bef9SDimitry Andric } 1434e8d8bef9SDimitry Andric 1435e8d8bef9SDimitry Andric bool isLosingCall(const State &StateAfterJoin, const CFGBlock *JoinBlock, 1436e8d8bef9SDimitry Andric unsigned ParameterIndex) const { 1437e8d8bef9SDimitry Andric // Let's check if the block represents DefinitelyCalled -> MaybeCalled 1438e8d8bef9SDimitry Andric // transition. 1439e8d8bef9SDimitry Andric return isLosingJoin(StateAfterJoin, JoinBlock, ParameterIndex, 1440e8d8bef9SDimitry Andric ParameterStatus::MaybeCalled, 1441e8d8bef9SDimitry Andric ParameterStatus::DefinitelyCalled); 1442e8d8bef9SDimitry Andric } 1443e8d8bef9SDimitry Andric 1444e8d8bef9SDimitry Andric bool isLosingEscape(const State &StateAfterJoin, const CFGBlock *JoinBlock, 1445e8d8bef9SDimitry Andric unsigned ParameterIndex) const { 1446e8d8bef9SDimitry Andric // Let's check if the block represents Escaped -> NotCalled transition. 1447e8d8bef9SDimitry Andric return isLosingJoin(StateAfterJoin, JoinBlock, ParameterIndex, 1448e8d8bef9SDimitry Andric ParameterStatus::NotCalled, ParameterStatus::Escaped); 1449e8d8bef9SDimitry Andric } 1450e8d8bef9SDimitry Andric 1451e8d8bef9SDimitry Andric bool isLosingJoin(const State &StateAfterJoin, const CFGBlock *JoinBlock, 1452e8d8bef9SDimitry Andric unsigned ParameterIndex, ParameterStatus::Kind AfterJoin, 1453e8d8bef9SDimitry Andric ParameterStatus::Kind BeforeJoin) const { 1454e8d8bef9SDimitry Andric assert(!ParameterStatus::isErrorStatus(BeforeJoin) && 1455e8d8bef9SDimitry Andric ParameterStatus::isErrorStatus(AfterJoin) && 1456e8d8bef9SDimitry Andric "It's not a losing join if statuses do not represent " 1457e8d8bef9SDimitry Andric "correct-to-error transition"); 1458e8d8bef9SDimitry Andric 1459e8d8bef9SDimitry Andric const ParameterStatus &CurrentStatus = 1460e8d8bef9SDimitry Andric StateAfterJoin.getStatusFor(ParameterIndex); 1461e8d8bef9SDimitry Andric 1462e8d8bef9SDimitry Andric return CurrentStatus.getKind() == AfterJoin && 1463e8d8bef9SDimitry Andric anySuccessorHasStatus(JoinBlock, ParameterIndex, BeforeJoin); 1464e8d8bef9SDimitry Andric } 1465e8d8bef9SDimitry Andric 1466e8d8bef9SDimitry Andric /// Return true if any of the successors of the given basic block has 1467e8d8bef9SDimitry Andric /// a specified status for the given parameter. 1468e8d8bef9SDimitry Andric bool anySuccessorHasStatus(const CFGBlock *Parent, unsigned ParameterIndex, 1469e8d8bef9SDimitry Andric ParameterStatus::Kind ToFind) const { 1470e8d8bef9SDimitry Andric return llvm::any_of( 1471e8d8bef9SDimitry Andric Parent->succs(), [this, ParameterIndex, ToFind](const CFGBlock *Succ) { 1472e8d8bef9SDimitry Andric return Succ && getState(Succ).getKindFor(ParameterIndex) == ToFind; 1473e8d8bef9SDimitry Andric }); 1474e8d8bef9SDimitry Andric } 1475e8d8bef9SDimitry Andric 1476e8d8bef9SDimitry Andric /// Check given expression that was discovered to escape. 1477e8d8bef9SDimitry Andric void checkEscapee(const Expr *E) { 1478e8d8bef9SDimitry Andric if (const ParmVarDecl *Parameter = findReferencedParmVarDecl(E)) { 1479e8d8bef9SDimitry Andric checkEscapee(*Parameter); 1480e8d8bef9SDimitry Andric } 1481e8d8bef9SDimitry Andric } 1482e8d8bef9SDimitry Andric 1483e8d8bef9SDimitry Andric /// Check given parameter that was discovered to escape. 1484e8d8bef9SDimitry Andric void checkEscapee(const ParmVarDecl &Parameter) { 1485e8d8bef9SDimitry Andric if (auto Index = getIndex(Parameter)) { 1486fe6060f1SDimitry Andric processEscapeFor(*Index); 1487e8d8bef9SDimitry Andric } 1488e8d8bef9SDimitry Andric } 1489e8d8bef9SDimitry Andric 1490e8d8bef9SDimitry Andric /// Mark all parameters in the current state as 'no-return'. 1491e8d8bef9SDimitry Andric void markNoReturn() { 1492e8d8bef9SDimitry Andric for (ParameterStatus &PS : CurrentState) { 1493e8d8bef9SDimitry Andric PS = ParameterStatus::NoReturn; 1494e8d8bef9SDimitry Andric } 1495e8d8bef9SDimitry Andric } 1496e8d8bef9SDimitry Andric 1497e8d8bef9SDimitry Andric /// Check if the given assignment represents suppression and act on it. 1498e8d8bef9SDimitry Andric void checkSuppression(const BinaryOperator *Assignment) { 1499e8d8bef9SDimitry Andric // Suppression has the following form: 1500e8d8bef9SDimitry Andric // parameter = 0; 1501e8d8bef9SDimitry Andric // 0 can be of any form (NULL, nil, etc.) 1502e8d8bef9SDimitry Andric if (auto Index = getIndexOfExpression(Assignment->getLHS())) { 1503e8d8bef9SDimitry Andric 1504e8d8bef9SDimitry Andric // We don't care what is written in the RHS, it could be whatever 1505e8d8bef9SDimitry Andric // we can interpret as 0. 1506e8d8bef9SDimitry Andric if (auto Constant = 1507e8d8bef9SDimitry Andric Assignment->getRHS()->IgnoreParenCasts()->getIntegerConstantExpr( 1508e8d8bef9SDimitry Andric AC.getASTContext())) { 1509e8d8bef9SDimitry Andric 1510e8d8bef9SDimitry Andric ParameterStatus &CurrentParamStatus = CurrentState.getStatusFor(*Index); 1511e8d8bef9SDimitry Andric 1512e8d8bef9SDimitry Andric if (0 == *Constant && CurrentParamStatus.seenAnyCalls()) { 1513e8d8bef9SDimitry Andric // Even though this suppression mechanism is introduced to tackle 1514e8d8bef9SDimitry Andric // false positives for multiple calls, the fact that the user has 1515e8d8bef9SDimitry Andric // to use suppression can also tell us that we couldn't figure out 1516e8d8bef9SDimitry Andric // how different paths cancel each other out. And if that is true, 1517e8d8bef9SDimitry Andric // we will most certainly have false positives about parameters not 1518e8d8bef9SDimitry Andric // being called on certain paths. 1519e8d8bef9SDimitry Andric // 1520e8d8bef9SDimitry Andric // For this reason, we abandon tracking this parameter altogether. 1521e8d8bef9SDimitry Andric CurrentParamStatus = ParameterStatus::Reported; 1522e8d8bef9SDimitry Andric } 1523e8d8bef9SDimitry Andric } 1524e8d8bef9SDimitry Andric } 1525e8d8bef9SDimitry Andric } 1526e8d8bef9SDimitry Andric 1527e8d8bef9SDimitry Andric public: 1528e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 1529e8d8bef9SDimitry Andric // Tree traversal methods 1530e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 1531e8d8bef9SDimitry Andric 1532e8d8bef9SDimitry Andric void VisitCallExpr(const CallExpr *Call) { 1533e8d8bef9SDimitry Andric // This call might be a direct call, i.e. a parameter call... 1534e8d8bef9SDimitry Andric checkDirectCall(Call); 1535e8d8bef9SDimitry Andric // ... or an indirect call, i.e. when parameter is an argument. 1536e8d8bef9SDimitry Andric checkIndirectCall(Call); 1537e8d8bef9SDimitry Andric } 1538e8d8bef9SDimitry Andric 1539e8d8bef9SDimitry Andric void VisitObjCMessageExpr(const ObjCMessageExpr *Message) { 1540e8d8bef9SDimitry Andric // The most common situation that we are defending against here is 1541e8d8bef9SDimitry Andric // copying a tracked parameter. 1542e8d8bef9SDimitry Andric if (const Expr *Receiver = Message->getInstanceReceiver()) { 1543e8d8bef9SDimitry Andric checkEscapee(Receiver); 1544e8d8bef9SDimitry Andric } 1545e8d8bef9SDimitry Andric // Message expressions unlike calls, could not be direct. 1546e8d8bef9SDimitry Andric checkIndirectCall(Message); 1547e8d8bef9SDimitry Andric } 1548e8d8bef9SDimitry Andric 1549e8d8bef9SDimitry Andric void VisitBlockExpr(const BlockExpr *Block) { 1550fe6060f1SDimitry Andric // Block expressions are tricky. It is a very common practice to capture 1551fe6060f1SDimitry Andric // completion handlers by blocks and use them there. 1552fe6060f1SDimitry Andric // For this reason, it is important to analyze blocks and report warnings 1553fe6060f1SDimitry Andric // for completion handler misuse in blocks. 1554e8d8bef9SDimitry Andric // 1555fe6060f1SDimitry Andric // However, it can be quite difficult to track how the block itself is being 1556fe6060f1SDimitry Andric // used. The full precise anlysis of that will be similar to alias analysis 1557fe6060f1SDimitry Andric // for completion handlers and can be too heavyweight for a compile-time 1558fe6060f1SDimitry Andric // diagnostic. Instead, we judge about the immediate use of the block. 1559fe6060f1SDimitry Andric // 1560fe6060f1SDimitry Andric // Here, we try to find a call expression where we know due to conventions, 1561fe6060f1SDimitry Andric // annotations, or other reasons that the block is called once and only 1562fe6060f1SDimitry Andric // once. 1563fe6060f1SDimitry Andric const Expr *CalledOnceCallSite = getBlockGuaraneedCallSite(Block); 1564fe6060f1SDimitry Andric 1565fe6060f1SDimitry Andric // We need to report this information to the handler because in the 1566fe6060f1SDimitry Andric // situation when we know that the block is called exactly once, we can be 1567fe6060f1SDimitry Andric // stricter in terms of reported diagnostics. 1568fe6060f1SDimitry Andric if (CalledOnceCallSite) { 1569fe6060f1SDimitry Andric Handler.handleBlockThatIsGuaranteedToBeCalledOnce(Block->getBlockDecl()); 1570fe6060f1SDimitry Andric } else { 1571fe6060f1SDimitry Andric Handler.handleBlockWithNoGuarantees(Block->getBlockDecl()); 1572fe6060f1SDimitry Andric } 1573fe6060f1SDimitry Andric 1574fe6060f1SDimitry Andric for (const auto &Capture : Block->getBlockDecl()->captures()) { 1575e8d8bef9SDimitry Andric if (const auto *Param = dyn_cast<ParmVarDecl>(Capture.getVariable())) { 1576fe6060f1SDimitry Andric if (auto Index = getIndex(*Param)) { 1577fe6060f1SDimitry Andric if (CalledOnceCallSite) { 1578fe6060f1SDimitry Andric // The call site of a block can be considered a call site of the 1579fe6060f1SDimitry Andric // captured parameter we track. 1580fe6060f1SDimitry Andric processCallFor(*Index, CalledOnceCallSite); 1581fe6060f1SDimitry Andric } else { 1582fe6060f1SDimitry Andric // We still should consider this block as an escape for parameter, 1583fe6060f1SDimitry Andric // if we don't know about its call site or the number of time it 1584fe6060f1SDimitry Andric // can be invoked. 1585fe6060f1SDimitry Andric processEscapeFor(*Index); 1586fe6060f1SDimitry Andric } 1587fe6060f1SDimitry Andric } 1588e8d8bef9SDimitry Andric } 1589e8d8bef9SDimitry Andric } 1590e8d8bef9SDimitry Andric } 1591e8d8bef9SDimitry Andric 1592e8d8bef9SDimitry Andric void VisitBinaryOperator(const BinaryOperator *Op) { 1593e8d8bef9SDimitry Andric if (Op->getOpcode() == clang::BO_Assign) { 1594e8d8bef9SDimitry Andric // Let's check if one of the tracked parameters is assigned into 1595e8d8bef9SDimitry Andric // something, and if it is we don't want to track extra variables, so we 1596e8d8bef9SDimitry Andric // consider it as an escapee. 1597e8d8bef9SDimitry Andric checkEscapee(Op->getRHS()); 1598e8d8bef9SDimitry Andric 1599e8d8bef9SDimitry Andric // Let's check whether this assignment is a suppression. 1600e8d8bef9SDimitry Andric checkSuppression(Op); 1601e8d8bef9SDimitry Andric } 1602e8d8bef9SDimitry Andric } 1603e8d8bef9SDimitry Andric 1604e8d8bef9SDimitry Andric void VisitDeclStmt(const DeclStmt *DS) { 1605e8d8bef9SDimitry Andric // Variable initialization is not assignment and should be handled 1606e8d8bef9SDimitry Andric // separately. 1607e8d8bef9SDimitry Andric // 1608e8d8bef9SDimitry Andric // Multiple declarations can be a part of declaration statement. 1609e8d8bef9SDimitry Andric for (const auto *Declaration : DS->getDeclGroup()) { 1610e8d8bef9SDimitry Andric if (const auto *Var = dyn_cast<VarDecl>(Declaration)) { 1611e8d8bef9SDimitry Andric if (Var->getInit()) { 1612e8d8bef9SDimitry Andric checkEscapee(Var->getInit()); 1613e8d8bef9SDimitry Andric } 1614fe6060f1SDimitry Andric 1615fe6060f1SDimitry Andric if (Var->hasAttr<CleanupAttr>()) { 1616fe6060f1SDimitry Andric FunctionHasCleanupVars = true; 1617fe6060f1SDimitry Andric } 1618e8d8bef9SDimitry Andric } 1619e8d8bef9SDimitry Andric } 1620e8d8bef9SDimitry Andric } 1621e8d8bef9SDimitry Andric 1622e8d8bef9SDimitry Andric void VisitCStyleCastExpr(const CStyleCastExpr *Cast) { 1623e8d8bef9SDimitry Andric // We consider '(void)parameter' as a manual no-op escape. 1624e8d8bef9SDimitry Andric // It should be used to explicitly tell the analysis that this parameter 1625e8d8bef9SDimitry Andric // is intentionally not called on this path. 1626e8d8bef9SDimitry Andric if (Cast->getType().getCanonicalType()->isVoidType()) { 1627e8d8bef9SDimitry Andric checkEscapee(Cast->getSubExpr()); 1628e8d8bef9SDimitry Andric } 1629e8d8bef9SDimitry Andric } 1630e8d8bef9SDimitry Andric 1631e8d8bef9SDimitry Andric void VisitObjCAtThrowStmt(const ObjCAtThrowStmt *) { 1632e8d8bef9SDimitry Andric // It is OK not to call marked parameters on exceptional paths. 1633e8d8bef9SDimitry Andric markNoReturn(); 1634e8d8bef9SDimitry Andric } 1635e8d8bef9SDimitry Andric 1636e8d8bef9SDimitry Andric private: 1637e8d8bef9SDimitry Andric unsigned size() const { return TrackedParams.size(); } 1638e8d8bef9SDimitry Andric 1639bdd1243dSDimitry Andric std::optional<unsigned> getIndexOfCallee(const CallExpr *Call) const { 1640e8d8bef9SDimitry Andric return getIndexOfExpression(Call->getCallee()); 1641e8d8bef9SDimitry Andric } 1642e8d8bef9SDimitry Andric 1643bdd1243dSDimitry Andric std::optional<unsigned> getIndexOfExpression(const Expr *E) const { 1644e8d8bef9SDimitry Andric if (const ParmVarDecl *Parameter = findReferencedParmVarDecl(E)) { 1645e8d8bef9SDimitry Andric return getIndex(*Parameter); 1646e8d8bef9SDimitry Andric } 1647e8d8bef9SDimitry Andric 1648bdd1243dSDimitry Andric return std::nullopt; 1649e8d8bef9SDimitry Andric } 1650e8d8bef9SDimitry Andric 1651bdd1243dSDimitry Andric std::optional<unsigned> getIndex(const ParmVarDecl &Parameter) const { 1652e8d8bef9SDimitry Andric // Expected number of parameters that we actually track is 1. 1653e8d8bef9SDimitry Andric // 1654e8d8bef9SDimitry Andric // Also, the maximum number of declared parameters could not be on a scale 1655e8d8bef9SDimitry Andric // of hundreds of thousands. 1656e8d8bef9SDimitry Andric // 1657e8d8bef9SDimitry Andric // In this setting, linear search seems reasonable and even performs better 1658e8d8bef9SDimitry Andric // than bisection. 1659e8d8bef9SDimitry Andric ParamSizedVector<const ParmVarDecl *>::const_iterator It = 1660e8d8bef9SDimitry Andric llvm::find(TrackedParams, &Parameter); 1661e8d8bef9SDimitry Andric 1662e8d8bef9SDimitry Andric if (It != TrackedParams.end()) { 1663e8d8bef9SDimitry Andric return It - TrackedParams.begin(); 1664e8d8bef9SDimitry Andric } 1665e8d8bef9SDimitry Andric 1666bdd1243dSDimitry Andric return std::nullopt; 1667e8d8bef9SDimitry Andric } 1668e8d8bef9SDimitry Andric 1669e8d8bef9SDimitry Andric const ParmVarDecl *getParameter(unsigned Index) const { 1670e8d8bef9SDimitry Andric assert(Index < TrackedParams.size()); 1671e8d8bef9SDimitry Andric return TrackedParams[Index]; 1672e8d8bef9SDimitry Andric } 1673e8d8bef9SDimitry Andric 1674e8d8bef9SDimitry Andric const CFG &FunctionCFG; 1675e8d8bef9SDimitry Andric AnalysisDeclContext &AC; 1676e8d8bef9SDimitry Andric CalledOnceCheckHandler &Handler; 1677e8d8bef9SDimitry Andric bool CheckConventionalParameters; 1678e8d8bef9SDimitry Andric // As of now, we turn this behavior off. So, we still are going to report 1679e8d8bef9SDimitry Andric // missing calls on paths that look like it was intentional. 1680e8d8bef9SDimitry Andric // Technically such reports are true positives, but they can make some users 1681e8d8bef9SDimitry Andric // grumpy because of the sheer number of warnings. 1682e8d8bef9SDimitry Andric // It can be turned back on if we decide that we want to have the other way 1683e8d8bef9SDimitry Andric // around. 1684e8d8bef9SDimitry Andric bool SuppressOnConventionalErrorPaths = false; 1685e8d8bef9SDimitry Andric 1686fe6060f1SDimitry Andric // The user can annotate variable declarations with cleanup functions, which 1687fe6060f1SDimitry Andric // essentially imposes a custom destructor logic on that variable. 1688fe6060f1SDimitry Andric // It is possible to use it, however, to call tracked parameters on all exits 1689fe6060f1SDimitry Andric // from the function. For this reason, we track the fact that the function 1690fe6060f1SDimitry Andric // actually has these. 1691fe6060f1SDimitry Andric bool FunctionHasCleanupVars = false; 1692fe6060f1SDimitry Andric 1693e8d8bef9SDimitry Andric State CurrentState; 1694e8d8bef9SDimitry Andric ParamSizedVector<const ParmVarDecl *> TrackedParams; 1695e8d8bef9SDimitry Andric CFGSizedVector<State> States; 1696e8d8bef9SDimitry Andric }; 1697e8d8bef9SDimitry Andric 1698e8d8bef9SDimitry Andric } // end anonymous namespace 1699e8d8bef9SDimitry Andric 1700e8d8bef9SDimitry Andric namespace clang { 1701e8d8bef9SDimitry Andric void checkCalledOnceParameters(AnalysisDeclContext &AC, 1702e8d8bef9SDimitry Andric CalledOnceCheckHandler &Handler, 1703e8d8bef9SDimitry Andric bool CheckConventionalParameters) { 1704e8d8bef9SDimitry Andric CalledOnceChecker::check(AC, Handler, CheckConventionalParameters); 1705e8d8bef9SDimitry Andric } 1706e8d8bef9SDimitry Andric } // end namespace clang 1707