xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp (revision d3c4637cbbd5f0a84811abe195098ce714a2cc32)
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 
22 bool hasPublicMethodInBaseClass(const CXXRecordDecl *R, StringRef NameToMatch) {
23   assert(R);
24   assert(R->hasDefinition());
25 
26   for (const CXXMethodDecl *MD : R->methods()) {
27     const auto MethodName = safeGetName(MD);
28     if (MethodName == NameToMatch && MD->getAccess() == AS_public)
29       return true;
30   }
31   return false;
32 }
33 
34 } // namespace
35 
36 namespace clang {
37 
38 std::optional<const clang::CXXRecordDecl *>
39 hasPublicMethodInBase(const CXXBaseSpecifier *Base, StringRef NameToMatch) {
40   assert(Base);
41 
42   const Type *T = Base->getType().getTypePtrOrNull();
43   if (!T)
44     return std::nullopt;
45 
46   const CXXRecordDecl *R = T->getAsCXXRecordDecl();
47   if (!R)
48     return std::nullopt;
49   if (!R->hasDefinition())
50     return std::nullopt;
51 
52   return hasPublicMethodInBaseClass(R, NameToMatch) ? R : nullptr;
53 }
54 
55 std::optional<bool> isSmartPtrCompatible(const CXXRecordDecl *R,
56                                          StringRef IncMethodName,
57                                          StringRef DecMethodName) {
58   assert(R);
59 
60   R = R->getDefinition();
61   if (!R)
62     return std::nullopt;
63 
64   bool hasRef = hasPublicMethodInBaseClass(R, IncMethodName);
65   bool hasDeref = hasPublicMethodInBaseClass(R, DecMethodName);
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 = [&](const CXXBaseSpecifier *Base,
74                                       CXXBasePath &) {
75     auto hasRefInBase = clang::hasPublicMethodInBase(Base, IncMethodName);
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 = [&](const CXXBaseSpecifier *Base,
90                                         CXXBasePath &) {
91     auto hasDerefInBase = clang::hasPublicMethodInBase(Base, DecMethodName);
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 
106 std::optional<bool> isRefCountable(const clang::CXXRecordDecl *R) {
107   return isSmartPtrCompatible(R, "ref", "deref");
108 }
109 
110 std::optional<bool> isCheckedPtrCapable(const clang::CXXRecordDecl *R) {
111   return isSmartPtrCompatible(R, "incrementCheckedPtrCount",
112                               "decrementCheckedPtrCount");
113 }
114 
115 bool isRefType(const std::string &Name) {
116   return Name == "Ref" || Name == "RefAllowingPartiallyDestroyed" ||
117          Name == "RefPtr" || Name == "RefPtrAllowingPartiallyDestroyed";
118 }
119 
120 bool isCheckedPtr(const std::string &Name) {
121   return Name == "CheckedPtr" || Name == "CheckedRef";
122 }
123 
124 bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
125   assert(F);
126   const std::string &FunctionName = safeGetName(F);
127 
128   return isRefType(FunctionName) || FunctionName == "adoptRef" ||
129          FunctionName == "UniqueRef" || FunctionName == "makeUniqueRef" ||
130          FunctionName == "makeUniqueRefWithoutFastMallocCheck"
131 
132          || FunctionName == "String" || FunctionName == "AtomString" ||
133          FunctionName == "UniqueString"
134          // FIXME: Implement as attribute.
135          || FunctionName == "Identifier";
136 }
137 
138 bool isCtorOfCheckedPtr(const clang::FunctionDecl *F) {
139   assert(F);
140   return isCheckedPtr(safeGetName(F));
141 }
142 
143 bool isCtorOfSafePtr(const clang::FunctionDecl *F) {
144   return isCtorOfRefCounted(F) || isCtorOfCheckedPtr(F);
145 }
146 
147 template <typename Predicate>
148 static bool isPtrOfType(const clang::QualType T, Predicate Pred) {
149   QualType type = T;
150   while (!type.isNull()) {
151     if (auto *elaboratedT = type->getAs<ElaboratedType>()) {
152       type = elaboratedT->desugar();
153       continue;
154     }
155     auto *SpecialT = type->getAs<TemplateSpecializationType>();
156     if (!SpecialT)
157       return false;
158     auto *Decl = SpecialT->getTemplateName().getAsTemplateDecl();
159     if (!Decl)
160       return false;
161     return Pred(Decl->getNameAsString());
162   }
163   return false;
164 }
165 
166 bool isSafePtrType(const clang::QualType T) {
167   return isPtrOfType(
168       T, [](auto Name) { return isRefType(Name) || isCheckedPtr(Name); });
169 }
170 
171 bool isOwnerPtrType(const clang::QualType T) {
172   return isPtrOfType(T, [](auto Name) {
173     return isRefType(Name) || isCheckedPtr(Name) || Name == "unique_ptr" ||
174            Name == "UniqueRef" || Name == "LazyUniqueRef";
175   });
176 }
177 
178 std::optional<bool> isUncounted(const QualType T) {
179   if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(T)) {
180     if (auto *Decl = Subst->getAssociatedDecl()) {
181       if (isRefType(safeGetName(Decl)))
182         return false;
183     }
184   }
185   return isUncounted(T->getAsCXXRecordDecl());
186 }
187 
188 std::optional<bool> isUnchecked(const QualType T) {
189   if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(T)) {
190     if (auto *Decl = Subst->getAssociatedDecl()) {
191       if (isCheckedPtr(safeGetName(Decl)))
192         return false;
193     }
194   }
195   return isUnchecked(T->getAsCXXRecordDecl());
196 }
197 
198 std::optional<bool> isUncounted(const CXXRecordDecl* Class)
199 {
200   // Keep isRefCounted first as it's cheaper.
201   if (!Class || isRefCounted(Class))
202     return false;
203 
204   std::optional<bool> IsRefCountable = isRefCountable(Class);
205   if (!IsRefCountable)
206     return std::nullopt;
207 
208   return (*IsRefCountable);
209 }
210 
211 std::optional<bool> isUnchecked(const CXXRecordDecl *Class) {
212   if (!Class || isCheckedPtr(Class))
213     return false; // Cheaper than below
214   return isCheckedPtrCapable(Class);
215 }
216 
217 std::optional<bool> isUncountedPtr(const QualType T) {
218   if (T->isPointerType() || T->isReferenceType()) {
219     if (auto *CXXRD = T->getPointeeCXXRecordDecl())
220       return isUncounted(CXXRD);
221   }
222   return false;
223 }
224 
225 std::optional<bool> isUncheckedPtr(const QualType T) {
226   if (T->isPointerType() || T->isReferenceType()) {
227     if (auto *CXXRD = T->getPointeeCXXRecordDecl())
228       return isUnchecked(CXXRD);
229   }
230   return false;
231 }
232 
233 std::optional<bool> isUnsafePtr(const QualType T) {
234   if (T->isPointerType() || T->isReferenceType()) {
235     if (auto *CXXRD = T->getPointeeCXXRecordDecl()) {
236       auto isUncountedPtr = isUncounted(CXXRD);
237       auto isUncheckedPtr = isUnchecked(CXXRD);
238       if (isUncountedPtr && isUncheckedPtr)
239         return *isUncountedPtr || *isUncheckedPtr;
240       if (isUncountedPtr)
241         return *isUncountedPtr;
242       return isUncheckedPtr;
243     }
244   }
245   return false;
246 }
247 
248 std::optional<bool> isGetterOfSafePtr(const CXXMethodDecl *M) {
249   assert(M);
250 
251   if (isa<CXXMethodDecl>(M)) {
252     const CXXRecordDecl *calleeMethodsClass = M->getParent();
253     auto className = safeGetName(calleeMethodsClass);
254     auto method = safeGetName(M);
255 
256     if (isCheckedPtr(className) && (method == "get" || method == "ptr"))
257       return true;
258 
259     if ((isRefType(className) && (method == "get" || method == "ptr")) ||
260         ((className == "String" || className == "AtomString" ||
261           className == "AtomStringImpl" || className == "UniqueString" ||
262           className == "UniqueStringImpl" || className == "Identifier") &&
263          method == "impl"))
264       return true;
265 
266     // Ref<T> -> T conversion
267     // FIXME: Currently allowing any Ref<T> -> whatever cast.
268     if (isRefType(className)) {
269       if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M))
270         return isUnsafePtr(maybeRefToRawOperator->getConversionType());
271     }
272 
273     if (isCheckedPtr(className)) {
274       if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M))
275         return isUnsafePtr(maybeRefToRawOperator->getConversionType());
276     }
277   }
278   return false;
279 }
280 
281 bool isRefCounted(const CXXRecordDecl *R) {
282   assert(R);
283   if (auto *TmplR = R->getTemplateInstantiationPattern()) {
284     // FIXME: String/AtomString/UniqueString
285     const auto &ClassName = safeGetName(TmplR);
286     return isRefType(ClassName);
287   }
288   return false;
289 }
290 
291 bool isCheckedPtr(const CXXRecordDecl *R) {
292   assert(R);
293   if (auto *TmplR = R->getTemplateInstantiationPattern()) {
294     const auto &ClassName = safeGetName(TmplR);
295     return isCheckedPtr(ClassName);
296   }
297   return false;
298 }
299 
300 bool isPtrConversion(const FunctionDecl *F) {
301   assert(F);
302   if (isCtorOfRefCounted(F))
303     return true;
304 
305   // FIXME: check # of params == 1
306   const auto FunctionName = safeGetName(F);
307   if (FunctionName == "getPtr" || FunctionName == "WeakPtr" ||
308       FunctionName == "dynamicDowncast" || FunctionName == "downcast" ||
309       FunctionName == "checkedDowncast" ||
310       FunctionName == "uncheckedDowncast" || FunctionName == "bitwise_cast")
311     return true;
312 
313   return false;
314 }
315 
316 bool isSingleton(const FunctionDecl *F) {
317   assert(F);
318   // FIXME: check # of params == 1
319   if (auto *MethodDecl = dyn_cast<CXXMethodDecl>(F)) {
320     if (!MethodDecl->isStatic())
321       return false;
322   }
323   const auto &NameStr = safeGetName(F);
324   StringRef Name = NameStr; // FIXME: Make safeGetName return StringRef.
325   return Name == "singleton" || Name.ends_with("Singleton");
326 }
327 
328 // We only care about statements so let's use the simple
329 // (non-recursive) visitor.
330 class TrivialFunctionAnalysisVisitor
331     : public ConstStmtVisitor<TrivialFunctionAnalysisVisitor, bool> {
332 
333   // Returns false if at least one child is non-trivial.
334   bool VisitChildren(const Stmt *S) {
335     for (const Stmt *Child : S->children()) {
336       if (Child && !Visit(Child))
337         return false;
338     }
339 
340     return true;
341   }
342 
343   template <typename StmtOrDecl, typename CheckFunction>
344   bool WithCachedResult(const StmtOrDecl *S, CheckFunction Function) {
345     auto CacheIt = Cache.find(S);
346     if (CacheIt != Cache.end())
347       return CacheIt->second;
348 
349     // Treat a recursive statement to be trivial until proven otherwise.
350     auto [RecursiveIt, IsNew] = RecursiveFn.insert(std::make_pair(S, true));
351     if (!IsNew)
352       return RecursiveIt->second;
353 
354     bool Result = Function();
355 
356     if (!Result) {
357       for (auto &It : RecursiveFn)
358         It.second = false;
359     }
360     RecursiveIt = RecursiveFn.find(S);
361     assert(RecursiveIt != RecursiveFn.end());
362     Result = RecursiveIt->second;
363     RecursiveFn.erase(RecursiveIt);
364     Cache[S] = Result;
365 
366     return Result;
367   }
368 
369 public:
370   using CacheTy = TrivialFunctionAnalysis::CacheTy;
371 
372   TrivialFunctionAnalysisVisitor(CacheTy &Cache) : Cache(Cache) {}
373 
374   bool IsFunctionTrivial(const Decl *D) {
375     return WithCachedResult(D, [&]() {
376       if (auto *CtorDecl = dyn_cast<CXXConstructorDecl>(D)) {
377         for (auto *CtorInit : CtorDecl->inits()) {
378           if (!Visit(CtorInit->getInit()))
379             return false;
380         }
381       }
382       const Stmt *Body = D->getBody();
383       if (!Body)
384         return false;
385       return Visit(Body);
386     });
387   }
388 
389   bool VisitStmt(const Stmt *S) {
390     // All statements are non-trivial unless overriden later.
391     // Don't even recurse into children by default.
392     return false;
393   }
394 
395   bool VisitCompoundStmt(const CompoundStmt *CS) {
396     // A compound statement is allowed as long each individual sub-statement
397     // is trivial.
398     return WithCachedResult(CS, [&]() { return VisitChildren(CS); });
399   }
400 
401   bool VisitReturnStmt(const ReturnStmt *RS) {
402     // A return statement is allowed as long as the return value is trivial.
403     if (auto *RV = RS->getRetValue())
404       return Visit(RV);
405     return true;
406   }
407 
408   bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); }
409   bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); }
410   bool VisitIfStmt(const IfStmt *IS) {
411     return WithCachedResult(IS, [&]() { return VisitChildren(IS); });
412   }
413   bool VisitForStmt(const ForStmt *FS) {
414     return WithCachedResult(FS, [&]() { return VisitChildren(FS); });
415   }
416   bool VisitCXXForRangeStmt(const CXXForRangeStmt *FS) {
417     return WithCachedResult(FS, [&]() { return VisitChildren(FS); });
418   }
419   bool VisitWhileStmt(const WhileStmt *WS) {
420     return WithCachedResult(WS, [&]() { return VisitChildren(WS); });
421   }
422   bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); }
423   bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); }
424   bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); }
425 
426   // break, continue, goto, and label statements are always trivial.
427   bool VisitBreakStmt(const BreakStmt *) { return true; }
428   bool VisitContinueStmt(const ContinueStmt *) { return true; }
429   bool VisitGotoStmt(const GotoStmt *) { return true; }
430   bool VisitLabelStmt(const LabelStmt *) { return true; }
431 
432   bool VisitUnaryOperator(const UnaryOperator *UO) {
433     // Unary operators are trivial if its operand is trivial except co_await.
434     return UO->getOpcode() != UO_Coawait && Visit(UO->getSubExpr());
435   }
436 
437   bool VisitBinaryOperator(const BinaryOperator *BO) {
438     // Binary operators are trivial if their operands are trivial.
439     return Visit(BO->getLHS()) && Visit(BO->getRHS());
440   }
441 
442   bool VisitCompoundAssignOperator(const CompoundAssignOperator *CAO) {
443     // Compound assignment operator such as |= is trivial if its
444     // subexpresssions are trivial.
445     return VisitChildren(CAO);
446   }
447 
448   bool VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE) {
449     return VisitChildren(ASE);
450   }
451 
452   bool VisitConditionalOperator(const ConditionalOperator *CO) {
453     // Ternary operators are trivial if their conditions & values are trivial.
454     return VisitChildren(CO);
455   }
456 
457   bool VisitAtomicExpr(const AtomicExpr *E) { return VisitChildren(E); }
458 
459   bool VisitStaticAssertDecl(const StaticAssertDecl *SAD) {
460     // Any static_assert is considered trivial.
461     return true;
462   }
463 
464   bool VisitCallExpr(const CallExpr *CE) {
465     if (!checkArguments(CE))
466       return false;
467 
468     auto *Callee = CE->getDirectCallee();
469     if (!Callee)
470       return false;
471     const auto &Name = safeGetName(Callee);
472 
473     if (Callee->isInStdNamespace() &&
474         (Name == "addressof" || Name == "forward" || Name == "move"))
475       return true;
476 
477     if (Name == "WTFCrashWithInfo" || Name == "WTFBreakpointTrap" ||
478         Name == "WTFReportBacktrace" ||
479         Name == "WTFCrashWithSecurityImplication" || Name == "WTFCrash" ||
480         Name == "WTFReportAssertionFailure" || Name == "isMainThread" ||
481         Name == "isMainThreadOrGCThread" || Name == "isMainRunLoop" ||
482         Name == "isWebThread" || Name == "isUIThread" ||
483         Name == "mayBeGCThread" || Name == "compilerFenceForCrash" ||
484         Name == "bitwise_cast" || Name.find("__builtin") == 0 ||
485         Name == "__libcpp_verbose_abort")
486       return true;
487 
488     return IsFunctionTrivial(Callee);
489   }
490 
491   bool
492   VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) {
493     // Non-type template paramter is compile time constant and trivial.
494     return true;
495   }
496 
497   bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E) {
498     return VisitChildren(E);
499   }
500 
501   bool VisitPredefinedExpr(const PredefinedExpr *E) {
502     // A predefined identifier such as "func" is considered trivial.
503     return true;
504   }
505 
506   bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE) {
507     if (!checkArguments(MCE))
508       return false;
509 
510     bool TrivialThis = Visit(MCE->getImplicitObjectArgument());
511     if (!TrivialThis)
512       return false;
513 
514     auto *Callee = MCE->getMethodDecl();
515     if (!Callee)
516       return false;
517 
518     auto Name = safeGetName(Callee);
519     if (Name == "ref" || Name == "incrementCheckedPtrCount")
520       return true;
521 
522     std::optional<bool> IsGetterOfRefCounted = isGetterOfSafePtr(Callee);
523     if (IsGetterOfRefCounted && *IsGetterOfRefCounted)
524       return true;
525 
526     // Recursively descend into the callee to confirm that it's trivial as well.
527     return IsFunctionTrivial(Callee);
528   }
529 
530   bool VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE) {
531     if (!checkArguments(OCE))
532       return false;
533     auto *Callee = OCE->getCalleeDecl();
534     if (!Callee)
535       return false;
536     // Recursively descend into the callee to confirm that it's trivial as well.
537     return IsFunctionTrivial(Callee);
538   }
539 
540   bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
541     if (auto *Expr = E->getExpr()) {
542       if (!Visit(Expr))
543         return false;
544     }
545     return true;
546   }
547 
548   bool checkArguments(const CallExpr *CE) {
549     for (const Expr *Arg : CE->arguments()) {
550       if (Arg && !Visit(Arg))
551         return false;
552     }
553     return true;
554   }
555 
556   bool VisitCXXConstructExpr(const CXXConstructExpr *CE) {
557     for (const Expr *Arg : CE->arguments()) {
558       if (Arg && !Visit(Arg))
559         return false;
560     }
561 
562     // Recursively descend into the callee to confirm that it's trivial.
563     return IsFunctionTrivial(CE->getConstructor());
564   }
565 
566   bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E) {
567     return IsFunctionTrivial(E->getConstructor());
568   }
569 
570   bool VisitCXXNewExpr(const CXXNewExpr *NE) { return VisitChildren(NE); }
571 
572   bool VisitImplicitCastExpr(const ImplicitCastExpr *ICE) {
573     return Visit(ICE->getSubExpr());
574   }
575 
576   bool VisitExplicitCastExpr(const ExplicitCastExpr *ECE) {
577     return Visit(ECE->getSubExpr());
578   }
579 
580   bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *VMT) {
581     return Visit(VMT->getSubExpr());
582   }
583 
584   bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE) {
585     if (auto *Temp = BTE->getTemporary()) {
586       if (!TrivialFunctionAnalysis::isTrivialImpl(Temp->getDestructor(), Cache))
587         return false;
588     }
589     return Visit(BTE->getSubExpr());
590   }
591 
592   bool VisitExprWithCleanups(const ExprWithCleanups *EWC) {
593     return Visit(EWC->getSubExpr());
594   }
595 
596   bool VisitParenExpr(const ParenExpr *PE) { return Visit(PE->getSubExpr()); }
597 
598   bool VisitInitListExpr(const InitListExpr *ILE) {
599     for (const Expr *Child : ILE->inits()) {
600       if (Child && !Visit(Child))
601         return false;
602     }
603     return true;
604   }
605 
606   bool VisitMemberExpr(const MemberExpr *ME) {
607     // Field access is allowed but the base pointer may itself be non-trivial.
608     return Visit(ME->getBase());
609   }
610 
611   bool VisitCXXThisExpr(const CXXThisExpr *CTE) {
612     // The expression 'this' is always trivial, be it explicit or implicit.
613     return true;
614   }
615 
616   bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
617     // nullptr is trivial.
618     return true;
619   }
620 
621   bool VisitDeclRefExpr(const DeclRefExpr *DRE) {
622     // The use of a variable is trivial.
623     return true;
624   }
625 
626   // Constant literal expressions are always trivial
627   bool VisitIntegerLiteral(const IntegerLiteral *E) { return true; }
628   bool VisitFloatingLiteral(const FloatingLiteral *E) { return true; }
629   bool VisitFixedPointLiteral(const FixedPointLiteral *E) { return true; }
630   bool VisitCharacterLiteral(const CharacterLiteral *E) { return true; }
631   bool VisitStringLiteral(const StringLiteral *E) { return true; }
632   bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { return true; }
633 
634   bool VisitConstantExpr(const ConstantExpr *CE) {
635     // Constant expressions are trivial.
636     return true;
637   }
638 
639 private:
640   CacheTy &Cache;
641   CacheTy RecursiveFn;
642 };
643 
644 bool TrivialFunctionAnalysis::isTrivialImpl(
645     const Decl *D, TrivialFunctionAnalysis::CacheTy &Cache) {
646   TrivialFunctionAnalysisVisitor V(Cache);
647   return V.IsFunctionTrivial(D);
648 }
649 
650 bool TrivialFunctionAnalysis::isTrivialImpl(
651     const Stmt *S, TrivialFunctionAnalysis::CacheTy &Cache) {
652   TrivialFunctionAnalysisVisitor V(Cache);
653   bool Result = V.Visit(S);
654   assert(Cache.contains(S) && "Top-level statement not properly cached!");
655   return Result;
656 }
657 
658 } // namespace clang
659