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