xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1  //=======- PtrTypesSemantics.cpp ---------------------------------*- C++ -*-==//
2  //
3  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4  // See https://llvm.org/LICENSE.txt for license information.
5  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6  //
7  //===----------------------------------------------------------------------===//
8  
9  #include "PtrTypesSemantics.h"
10  #include "ASTUtils.h"
11  #include "clang/AST/CXXInheritance.h"
12  #include "clang/AST/Decl.h"
13  #include "clang/AST/DeclCXX.h"
14  #include "clang/AST/ExprCXX.h"
15  #include "clang/AST/StmtVisitor.h"
16  #include <optional>
17  
18  using namespace clang;
19  
20  namespace {
21  
hasPublicMethodInBaseClass(const CXXRecordDecl * R,const char * NameToMatch)22  bool hasPublicMethodInBaseClass(const CXXRecordDecl *R,
23                                  const char *NameToMatch) {
24    assert(R);
25    assert(R->hasDefinition());
26  
27    for (const CXXMethodDecl *MD : R->methods()) {
28      const auto MethodName = safeGetName(MD);
29      if (MethodName == NameToMatch && MD->getAccess() == AS_public)
30        return true;
31    }
32    return false;
33  }
34  
35  } // namespace
36  
37  namespace clang {
38  
39  std::optional<const clang::CXXRecordDecl *>
hasPublicMethodInBase(const CXXBaseSpecifier * Base,const char * NameToMatch)40  hasPublicMethodInBase(const CXXBaseSpecifier *Base, const char *NameToMatch) {
41    assert(Base);
42  
43    const Type *T = Base->getType().getTypePtrOrNull();
44    if (!T)
45      return std::nullopt;
46  
47    const CXXRecordDecl *R = T->getAsCXXRecordDecl();
48    if (!R)
49      return std::nullopt;
50    if (!R->hasDefinition())
51      return std::nullopt;
52  
53    return hasPublicMethodInBaseClass(R, NameToMatch) ? R : nullptr;
54  }
55  
isRefCountable(const CXXRecordDecl * R)56  std::optional<bool> isRefCountable(const CXXRecordDecl* R)
57  {
58    assert(R);
59  
60    R = R->getDefinition();
61    if (!R)
62      return std::nullopt;
63  
64    bool hasRef = hasPublicMethodInBaseClass(R, "ref");
65    bool hasDeref = hasPublicMethodInBaseClass(R, "deref");
66    if (hasRef && hasDeref)
67      return true;
68  
69    CXXBasePaths Paths;
70    Paths.setOrigin(const_cast<CXXRecordDecl *>(R));
71  
72    bool AnyInconclusiveBase = false;
73    const auto hasPublicRefInBase =
74        [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) {
75          auto hasRefInBase = clang::hasPublicMethodInBase(Base, "ref");
76          if (!hasRefInBase) {
77            AnyInconclusiveBase = true;
78            return false;
79          }
80          return (*hasRefInBase) != nullptr;
81        };
82  
83    hasRef = hasRef || R->lookupInBases(hasPublicRefInBase, Paths,
84                                        /*LookupInDependent =*/true);
85    if (AnyInconclusiveBase)
86      return std::nullopt;
87  
88    Paths.clear();
89    const auto hasPublicDerefInBase =
90        [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) {
91          auto hasDerefInBase = clang::hasPublicMethodInBase(Base, "deref");
92          if (!hasDerefInBase) {
93            AnyInconclusiveBase = true;
94            return false;
95          }
96          return (*hasDerefInBase) != nullptr;
97        };
98    hasDeref = hasDeref || R->lookupInBases(hasPublicDerefInBase, Paths,
99                                            /*LookupInDependent =*/true);
100    if (AnyInconclusiveBase)
101      return std::nullopt;
102  
103    return hasRef && hasDeref;
104  }
105  
isRefType(const std::string & Name)106  bool isRefType(const std::string &Name) {
107    return Name == "Ref" || Name == "RefAllowingPartiallyDestroyed" ||
108           Name == "RefPtr" || Name == "RefPtrAllowingPartiallyDestroyed";
109  }
110  
isCtorOfRefCounted(const clang::FunctionDecl * F)111  bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
112    assert(F);
113    const std::string &FunctionName = safeGetName(F);
114  
115    return isRefType(FunctionName) || FunctionName == "makeRef" ||
116           FunctionName == "makeRefPtr" || FunctionName == "UniqueRef" ||
117           FunctionName == "makeUniqueRef" ||
118           FunctionName == "makeUniqueRefWithoutFastMallocCheck"
119  
120           || FunctionName == "String" || FunctionName == "AtomString" ||
121           FunctionName == "UniqueString"
122           // FIXME: Implement as attribute.
123           || FunctionName == "Identifier";
124  }
125  
isReturnValueRefCounted(const clang::FunctionDecl * F)126  bool isReturnValueRefCounted(const clang::FunctionDecl *F) {
127    assert(F);
128    QualType type = F->getReturnType();
129    while (!type.isNull()) {
130      if (auto *elaboratedT = type->getAs<ElaboratedType>()) {
131        type = elaboratedT->desugar();
132        continue;
133      }
134      if (auto *specialT = type->getAs<TemplateSpecializationType>()) {
135        if (auto *decl = specialT->getTemplateName().getAsTemplateDecl()) {
136          auto name = decl->getNameAsString();
137          return isRefType(name);
138        }
139        return false;
140      }
141      return false;
142    }
143    return false;
144  }
145  
isUncounted(const CXXRecordDecl * Class)146  std::optional<bool> isUncounted(const CXXRecordDecl* Class)
147  {
148    // Keep isRefCounted first as it's cheaper.
149    if (isRefCounted(Class))
150      return false;
151  
152    std::optional<bool> IsRefCountable = isRefCountable(Class);
153    if (!IsRefCountable)
154      return std::nullopt;
155  
156    return (*IsRefCountable);
157  }
158  
isUncountedPtr(const Type * T)159  std::optional<bool> isUncountedPtr(const Type* T)
160  {
161    assert(T);
162  
163    if (T->isPointerType() || T->isReferenceType()) {
164      if (auto *CXXRD = T->getPointeeCXXRecordDecl()) {
165        return isUncounted(CXXRD);
166      }
167    }
168    return false;
169  }
170  
isGetterOfRefCounted(const CXXMethodDecl * M)171  std::optional<bool> isGetterOfRefCounted(const CXXMethodDecl* M)
172  {
173    assert(M);
174  
175    if (isa<CXXMethodDecl>(M)) {
176      const CXXRecordDecl *calleeMethodsClass = M->getParent();
177      auto className = safeGetName(calleeMethodsClass);
178      auto method = safeGetName(M);
179  
180      if ((isRefType(className) && (method == "get" || method == "ptr")) ||
181          ((className == "String" || className == "AtomString" ||
182            className == "AtomStringImpl" || className == "UniqueString" ||
183            className == "UniqueStringImpl" || className == "Identifier") &&
184           method == "impl"))
185        return true;
186  
187      // Ref<T> -> T conversion
188      // FIXME: Currently allowing any Ref<T> -> whatever cast.
189      if (isRefType(className)) {
190        if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
191          if (auto *targetConversionType =
192                  maybeRefToRawOperator->getConversionType().getTypePtrOrNull()) {
193            return isUncountedPtr(targetConversionType);
194          }
195        }
196      }
197    }
198    return false;
199  }
200  
isRefCounted(const CXXRecordDecl * R)201  bool isRefCounted(const CXXRecordDecl *R) {
202    assert(R);
203    if (auto *TmplR = R->getTemplateInstantiationPattern()) {
204      // FIXME: String/AtomString/UniqueString
205      const auto &ClassName = safeGetName(TmplR);
206      return isRefType(ClassName);
207    }
208    return false;
209  }
210  
isPtrConversion(const FunctionDecl * F)211  bool isPtrConversion(const FunctionDecl *F) {
212    assert(F);
213    if (isCtorOfRefCounted(F))
214      return true;
215  
216    // FIXME: check # of params == 1
217    const auto FunctionName = safeGetName(F);
218    if (FunctionName == "getPtr" || FunctionName == "WeakPtr" ||
219        FunctionName == "dynamicDowncast" || FunctionName == "downcast" ||
220        FunctionName == "checkedDowncast" ||
221        FunctionName == "uncheckedDowncast" || FunctionName == "bitwise_cast")
222      return true;
223  
224    return false;
225  }
226  
isSingleton(const FunctionDecl * F)227  bool isSingleton(const FunctionDecl *F) {
228    assert(F);
229    // FIXME: check # of params == 1
230    if (auto *MethodDecl = dyn_cast<CXXMethodDecl>(F)) {
231      if (!MethodDecl->isStatic())
232        return false;
233    }
234    const auto &Name = safeGetName(F);
235    std::string SingletonStr = "singleton";
236    auto index = Name.find(SingletonStr);
237    return index != std::string::npos &&
238           index == Name.size() - SingletonStr.size();
239  }
240  
241  // We only care about statements so let's use the simple
242  // (non-recursive) visitor.
243  class TrivialFunctionAnalysisVisitor
244      : public ConstStmtVisitor<TrivialFunctionAnalysisVisitor, bool> {
245  
246    // Returns false if at least one child is non-trivial.
VisitChildren(const Stmt * S)247    bool VisitChildren(const Stmt *S) {
248      for (const Stmt *Child : S->children()) {
249        if (Child && !Visit(Child))
250          return false;
251      }
252  
253      return true;
254    }
255  
256    template <typename CheckFunction>
WithCachedResult(const Stmt * S,CheckFunction Function)257    bool WithCachedResult(const Stmt *S, CheckFunction Function) {
258      // If the statement isn't in the cache, conservatively assume that
259      // it's not trivial until analysis completes. Insert false to the cache
260      // first to avoid infinite recursion.
261      auto [It, IsNew] = Cache.insert(std::make_pair(S, false));
262      if (!IsNew)
263        return It->second;
264      bool Result = Function();
265      Cache[S] = Result;
266      return Result;
267    }
268  
269  public:
270    using CacheTy = TrivialFunctionAnalysis::CacheTy;
271  
TrivialFunctionAnalysisVisitor(CacheTy & Cache)272    TrivialFunctionAnalysisVisitor(CacheTy &Cache) : Cache(Cache) {}
273  
IsFunctionTrivial(const Decl * D)274    bool IsFunctionTrivial(const Decl *D) {
275      auto CacheIt = Cache.find(D);
276      if (CacheIt != Cache.end())
277        return CacheIt->second;
278  
279      // Treat a recursive function call to be trivial until proven otherwise.
280      auto [RecursiveIt, IsNew] = RecursiveFn.insert(std::make_pair(D, true));
281      if (!IsNew)
282        return RecursiveIt->second;
283  
284      bool Result = [&]() {
285        if (auto *CtorDecl = dyn_cast<CXXConstructorDecl>(D)) {
286          for (auto *CtorInit : CtorDecl->inits()) {
287            if (!Visit(CtorInit->getInit()))
288              return false;
289          }
290        }
291        const Stmt *Body = D->getBody();
292        if (!Body)
293          return false;
294        return Visit(Body);
295      }();
296  
297      if (!Result) {
298        // D and its mutually recursive callers are all non-trivial.
299        for (auto &It : RecursiveFn)
300          It.second = false;
301      }
302      RecursiveIt = RecursiveFn.find(D);
303      assert(RecursiveIt != RecursiveFn.end());
304      Result = RecursiveIt->second;
305      RecursiveFn.erase(RecursiveIt);
306      Cache[D] = Result;
307  
308      return Result;
309    }
310  
VisitStmt(const Stmt * S)311    bool VisitStmt(const Stmt *S) {
312      // All statements are non-trivial unless overriden later.
313      // Don't even recurse into children by default.
314      return false;
315    }
316  
VisitCompoundStmt(const CompoundStmt * CS)317    bool VisitCompoundStmt(const CompoundStmt *CS) {
318      // A compound statement is allowed as long each individual sub-statement
319      // is trivial.
320      return WithCachedResult(CS, [&]() { return VisitChildren(CS); });
321    }
322  
VisitReturnStmt(const ReturnStmt * RS)323    bool VisitReturnStmt(const ReturnStmt *RS) {
324      // A return statement is allowed as long as the return value is trivial.
325      if (auto *RV = RS->getRetValue())
326        return Visit(RV);
327      return true;
328    }
329  
VisitDeclStmt(const DeclStmt * DS)330    bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); }
VisitDoStmt(const DoStmt * DS)331    bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); }
VisitIfStmt(const IfStmt * IS)332    bool VisitIfStmt(const IfStmt *IS) {
333      return WithCachedResult(IS, [&]() { return VisitChildren(IS); });
334    }
VisitForStmt(const ForStmt * FS)335    bool VisitForStmt(const ForStmt *FS) {
336      return WithCachedResult(FS, [&]() { return VisitChildren(FS); });
337    }
VisitCXXForRangeStmt(const CXXForRangeStmt * FS)338    bool VisitCXXForRangeStmt(const CXXForRangeStmt *FS) {
339      return WithCachedResult(FS, [&]() { return VisitChildren(FS); });
340    }
VisitWhileStmt(const WhileStmt * WS)341    bool VisitWhileStmt(const WhileStmt *WS) {
342      return WithCachedResult(WS, [&]() { return VisitChildren(WS); });
343    }
VisitSwitchStmt(const SwitchStmt * SS)344    bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); }
VisitCaseStmt(const CaseStmt * CS)345    bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); }
VisitDefaultStmt(const DefaultStmt * DS)346    bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); }
347  
348    // break, continue, goto, and label statements are always trivial.
VisitBreakStmt(const BreakStmt *)349    bool VisitBreakStmt(const BreakStmt *) { return true; }
VisitContinueStmt(const ContinueStmt *)350    bool VisitContinueStmt(const ContinueStmt *) { return true; }
VisitGotoStmt(const GotoStmt *)351    bool VisitGotoStmt(const GotoStmt *) { return true; }
VisitLabelStmt(const LabelStmt *)352    bool VisitLabelStmt(const LabelStmt *) { return true; }
353  
VisitUnaryOperator(const UnaryOperator * UO)354    bool VisitUnaryOperator(const UnaryOperator *UO) {
355      // Unary operators are trivial if its operand is trivial except co_await.
356      return UO->getOpcode() != UO_Coawait && Visit(UO->getSubExpr());
357    }
358  
VisitBinaryOperator(const BinaryOperator * BO)359    bool VisitBinaryOperator(const BinaryOperator *BO) {
360      // Binary operators are trivial if their operands are trivial.
361      return Visit(BO->getLHS()) && Visit(BO->getRHS());
362    }
363  
VisitCompoundAssignOperator(const CompoundAssignOperator * CAO)364    bool VisitCompoundAssignOperator(const CompoundAssignOperator *CAO) {
365      // Compound assignment operator such as |= is trivial if its
366      // subexpresssions are trivial.
367      return VisitChildren(CAO);
368    }
369  
VisitArraySubscriptExpr(const ArraySubscriptExpr * ASE)370    bool VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE) {
371      return VisitChildren(ASE);
372    }
373  
VisitConditionalOperator(const ConditionalOperator * CO)374    bool VisitConditionalOperator(const ConditionalOperator *CO) {
375      // Ternary operators are trivial if their conditions & values are trivial.
376      return VisitChildren(CO);
377    }
378  
VisitAtomicExpr(const AtomicExpr * E)379    bool VisitAtomicExpr(const AtomicExpr *E) { return VisitChildren(E); }
380  
VisitStaticAssertDecl(const StaticAssertDecl * SAD)381    bool VisitStaticAssertDecl(const StaticAssertDecl *SAD) {
382      // Any static_assert is considered trivial.
383      return true;
384    }
385  
VisitCallExpr(const CallExpr * CE)386    bool VisitCallExpr(const CallExpr *CE) {
387      if (!checkArguments(CE))
388        return false;
389  
390      auto *Callee = CE->getDirectCallee();
391      if (!Callee)
392        return false;
393      const auto &Name = safeGetName(Callee);
394  
395      if (Callee->isInStdNamespace() &&
396          (Name == "addressof" || Name == "forward" || Name == "move"))
397        return true;
398  
399      if (Name == "WTFCrashWithInfo" || Name == "WTFBreakpointTrap" ||
400          Name == "WTFCrashWithSecurityImplication" || Name == "WTFCrash" ||
401          Name == "WTFReportAssertionFailure" || Name == "isMainThread" ||
402          Name == "isMainThreadOrGCThread" || Name == "isMainRunLoop" ||
403          Name == "isWebThread" || Name == "isUIThread" ||
404          Name == "mayBeGCThread" || Name == "compilerFenceForCrash" ||
405          Name == "bitwise_cast" || Name.find("__builtin") == 0)
406        return true;
407  
408      return IsFunctionTrivial(Callee);
409    }
410  
411    bool
VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr * E)412    VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) {
413      // Non-type template paramter is compile time constant and trivial.
414      return true;
415    }
416  
VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr * E)417    bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E) {
418      return VisitChildren(E);
419    }
420  
VisitPredefinedExpr(const PredefinedExpr * E)421    bool VisitPredefinedExpr(const PredefinedExpr *E) {
422      // A predefined identifier such as "func" is considered trivial.
423      return true;
424    }
425  
VisitCXXMemberCallExpr(const CXXMemberCallExpr * MCE)426    bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE) {
427      if (!checkArguments(MCE))
428        return false;
429  
430      bool TrivialThis = Visit(MCE->getImplicitObjectArgument());
431      if (!TrivialThis)
432        return false;
433  
434      auto *Callee = MCE->getMethodDecl();
435      if (!Callee)
436        return false;
437  
438      std::optional<bool> IsGetterOfRefCounted = isGetterOfRefCounted(Callee);
439      if (IsGetterOfRefCounted && *IsGetterOfRefCounted)
440        return true;
441  
442      // Recursively descend into the callee to confirm that it's trivial as well.
443      return IsFunctionTrivial(Callee);
444    }
445  
VisitCXXOperatorCallExpr(const CXXOperatorCallExpr * OCE)446    bool VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE) {
447      if (!checkArguments(OCE))
448        return false;
449      auto *Callee = OCE->getCalleeDecl();
450      if (!Callee)
451        return false;
452      // Recursively descend into the callee to confirm that it's trivial as well.
453      return IsFunctionTrivial(Callee);
454    }
455  
VisitCXXDefaultArgExpr(const CXXDefaultArgExpr * E)456    bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
457      if (auto *Expr = E->getExpr()) {
458        if (!Visit(Expr))
459          return false;
460      }
461      return true;
462    }
463  
checkArguments(const CallExpr * CE)464    bool checkArguments(const CallExpr *CE) {
465      for (const Expr *Arg : CE->arguments()) {
466        if (Arg && !Visit(Arg))
467          return false;
468      }
469      return true;
470    }
471  
VisitCXXConstructExpr(const CXXConstructExpr * CE)472    bool VisitCXXConstructExpr(const CXXConstructExpr *CE) {
473      for (const Expr *Arg : CE->arguments()) {
474        if (Arg && !Visit(Arg))
475          return false;
476      }
477  
478      // Recursively descend into the callee to confirm that it's trivial.
479      return IsFunctionTrivial(CE->getConstructor());
480    }
481  
VisitCXXNewExpr(const CXXNewExpr * NE)482    bool VisitCXXNewExpr(const CXXNewExpr *NE) { return VisitChildren(NE); }
483  
VisitImplicitCastExpr(const ImplicitCastExpr * ICE)484    bool VisitImplicitCastExpr(const ImplicitCastExpr *ICE) {
485      return Visit(ICE->getSubExpr());
486    }
487  
VisitExplicitCastExpr(const ExplicitCastExpr * ECE)488    bool VisitExplicitCastExpr(const ExplicitCastExpr *ECE) {
489      return Visit(ECE->getSubExpr());
490    }
491  
VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr * VMT)492    bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *VMT) {
493      return Visit(VMT->getSubExpr());
494    }
495  
VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr * BTE)496    bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE) {
497      if (auto *Temp = BTE->getTemporary()) {
498        if (!TrivialFunctionAnalysis::isTrivialImpl(Temp->getDestructor(), Cache))
499          return false;
500      }
501      return Visit(BTE->getSubExpr());
502    }
503  
VisitExprWithCleanups(const ExprWithCleanups * EWC)504    bool VisitExprWithCleanups(const ExprWithCleanups *EWC) {
505      return Visit(EWC->getSubExpr());
506    }
507  
VisitParenExpr(const ParenExpr * PE)508    bool VisitParenExpr(const ParenExpr *PE) { return Visit(PE->getSubExpr()); }
509  
VisitInitListExpr(const InitListExpr * ILE)510    bool VisitInitListExpr(const InitListExpr *ILE) {
511      for (const Expr *Child : ILE->inits()) {
512        if (Child && !Visit(Child))
513          return false;
514      }
515      return true;
516    }
517  
VisitMemberExpr(const MemberExpr * ME)518    bool VisitMemberExpr(const MemberExpr *ME) {
519      // Field access is allowed but the base pointer may itself be non-trivial.
520      return Visit(ME->getBase());
521    }
522  
VisitCXXThisExpr(const CXXThisExpr * CTE)523    bool VisitCXXThisExpr(const CXXThisExpr *CTE) {
524      // The expression 'this' is always trivial, be it explicit or implicit.
525      return true;
526    }
527  
VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr * E)528    bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
529      // nullptr is trivial.
530      return true;
531    }
532  
VisitDeclRefExpr(const DeclRefExpr * DRE)533    bool VisitDeclRefExpr(const DeclRefExpr *DRE) {
534      // The use of a variable is trivial.
535      return true;
536    }
537  
538    // Constant literal expressions are always trivial
VisitIntegerLiteral(const IntegerLiteral * E)539    bool VisitIntegerLiteral(const IntegerLiteral *E) { return true; }
VisitFloatingLiteral(const FloatingLiteral * E)540    bool VisitFloatingLiteral(const FloatingLiteral *E) { return true; }
VisitFixedPointLiteral(const FixedPointLiteral * E)541    bool VisitFixedPointLiteral(const FixedPointLiteral *E) { return true; }
VisitCharacterLiteral(const CharacterLiteral * E)542    bool VisitCharacterLiteral(const CharacterLiteral *E) { return true; }
VisitStringLiteral(const StringLiteral * E)543    bool VisitStringLiteral(const StringLiteral *E) { return true; }
VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr * E)544    bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { return true; }
545  
VisitConstantExpr(const ConstantExpr * CE)546    bool VisitConstantExpr(const ConstantExpr *CE) {
547      // Constant expressions are trivial.
548      return true;
549    }
550  
551  private:
552    CacheTy &Cache;
553    CacheTy RecursiveFn;
554  };
555  
isTrivialImpl(const Decl * D,TrivialFunctionAnalysis::CacheTy & Cache)556  bool TrivialFunctionAnalysis::isTrivialImpl(
557      const Decl *D, TrivialFunctionAnalysis::CacheTy &Cache) {
558    TrivialFunctionAnalysisVisitor V(Cache);
559    return V.IsFunctionTrivial(D);
560  }
561  
isTrivialImpl(const Stmt * S,TrivialFunctionAnalysis::CacheTy & Cache)562  bool TrivialFunctionAnalysis::isTrivialImpl(
563      const Stmt *S, TrivialFunctionAnalysis::CacheTy &Cache) {
564    // If the statement isn't in the cache, conservatively assume that
565    // it's not trivial until analysis completes. Unlike a function case,
566    // we don't insert an entry into the cache until Visit returns
567    // since Visit* functions themselves make use of the cache.
568  
569    TrivialFunctionAnalysisVisitor V(Cache);
570    bool Result = V.Visit(S);
571    assert(Cache.contains(S) && "Top-level statement not properly cached!");
572    return Result;
573  }
574  
575  } // namespace clang
576