xref: /freebsd/contrib/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //=== AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis ------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines analysis_warnings::[Policy,Executor].
100b57cec5SDimitry Andric // Together they are used by Sema to issue warnings based on inexpensive
110b57cec5SDimitry Andric // static analysis algorithms in libAnalysis.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "clang/Sema/AnalysisBasedWarnings.h"
1606c3fb27SDimitry Andric #include "clang/AST/Decl.h"
170b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h"
180b57cec5SDimitry Andric #include "clang/AST/DeclObjC.h"
190b57cec5SDimitry Andric #include "clang/AST/EvaluatedExprVisitor.h"
20bdd1243dSDimitry Andric #include "clang/AST/Expr.h"
210b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h"
220b57cec5SDimitry Andric #include "clang/AST/ExprObjC.h"
23bdd1243dSDimitry Andric #include "clang/AST/OperationKinds.h"
240b57cec5SDimitry Andric #include "clang/AST/ParentMap.h"
250b57cec5SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h"
260b57cec5SDimitry Andric #include "clang/AST/StmtCXX.h"
270b57cec5SDimitry Andric #include "clang/AST/StmtObjC.h"
280b57cec5SDimitry Andric #include "clang/AST/StmtVisitor.h"
2906c3fb27SDimitry Andric #include "clang/AST/Type.h"
300b57cec5SDimitry Andric #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
31e8d8bef9SDimitry Andric #include "clang/Analysis/Analyses/CalledOnceCheck.h"
320b57cec5SDimitry Andric #include "clang/Analysis/Analyses/Consumed.h"
330b57cec5SDimitry Andric #include "clang/Analysis/Analyses/ReachableCode.h"
340b57cec5SDimitry Andric #include "clang/Analysis/Analyses/ThreadSafety.h"
350b57cec5SDimitry Andric #include "clang/Analysis/Analyses/UninitializedValues.h"
36bdd1243dSDimitry Andric #include "clang/Analysis/Analyses/UnsafeBufferUsage.h"
370b57cec5SDimitry Andric #include "clang/Analysis/AnalysisDeclContext.h"
380b57cec5SDimitry Andric #include "clang/Analysis/CFG.h"
390b57cec5SDimitry Andric #include "clang/Analysis/CFGStmtMap.h"
4006c3fb27SDimitry Andric #include "clang/Basic/Diagnostic.h"
41*0fca6ea1SDimitry Andric #include "clang/Basic/DiagnosticSema.h"
420b57cec5SDimitry Andric #include "clang/Basic/SourceLocation.h"
430b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
440b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
450b57cec5SDimitry Andric #include "clang/Sema/ScopeInfo.h"
460b57cec5SDimitry Andric #include "clang/Sema/SemaInternal.h"
47e8d8bef9SDimitry Andric #include "llvm/ADT/ArrayRef.h"
480b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h"
490b57cec5SDimitry Andric #include "llvm/ADT/MapVector.h"
5006c3fb27SDimitry Andric #include "llvm/ADT/STLFunctionalExtras.h"
510b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
520b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
530b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
540b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
550b57cec5SDimitry Andric #include <algorithm>
560b57cec5SDimitry Andric #include <deque>
570b57cec5SDimitry Andric #include <iterator>
58bdd1243dSDimitry Andric #include <optional>
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric using namespace clang;
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
630b57cec5SDimitry Andric // Unreachable code analysis.
640b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric namespace {
670b57cec5SDimitry Andric   class UnreachableCodeHandler : public reachable_code::Callback {
680b57cec5SDimitry Andric     Sema &S;
690b57cec5SDimitry Andric     SourceRange PreviousSilenceableCondVal;
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   public:
UnreachableCodeHandler(Sema & s)720b57cec5SDimitry Andric     UnreachableCodeHandler(Sema &s) : S(s) {}
730b57cec5SDimitry Andric 
HandleUnreachable(reachable_code::UnreachableKind UK,SourceLocation L,SourceRange SilenceableCondVal,SourceRange R1,SourceRange R2,bool HasFallThroughAttr)7406c3fb27SDimitry Andric     void HandleUnreachable(reachable_code::UnreachableKind UK, SourceLocation L,
7506c3fb27SDimitry Andric                            SourceRange SilenceableCondVal, SourceRange R1,
7606c3fb27SDimitry Andric                            SourceRange R2, bool HasFallThroughAttr) override {
7706c3fb27SDimitry Andric       // If the diagnosed code is `[[fallthrough]];` and
7806c3fb27SDimitry Andric       // `-Wunreachable-code-fallthrough` is  enabled, suppress `code will never
7906c3fb27SDimitry Andric       // be executed` warning to avoid generating diagnostic twice
8006c3fb27SDimitry Andric       if (HasFallThroughAttr &&
8106c3fb27SDimitry Andric           !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr,
8206c3fb27SDimitry Andric                                         SourceLocation()))
8306c3fb27SDimitry Andric         return;
8406c3fb27SDimitry Andric 
850b57cec5SDimitry Andric       // Avoid reporting multiple unreachable code diagnostics that are
860b57cec5SDimitry Andric       // triggered by the same conditional value.
870b57cec5SDimitry Andric       if (PreviousSilenceableCondVal.isValid() &&
880b57cec5SDimitry Andric           SilenceableCondVal.isValid() &&
890b57cec5SDimitry Andric           PreviousSilenceableCondVal == SilenceableCondVal)
900b57cec5SDimitry Andric         return;
910b57cec5SDimitry Andric       PreviousSilenceableCondVal = SilenceableCondVal;
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric       unsigned diag = diag::warn_unreachable;
940b57cec5SDimitry Andric       switch (UK) {
950b57cec5SDimitry Andric         case reachable_code::UK_Break:
960b57cec5SDimitry Andric           diag = diag::warn_unreachable_break;
970b57cec5SDimitry Andric           break;
980b57cec5SDimitry Andric         case reachable_code::UK_Return:
990b57cec5SDimitry Andric           diag = diag::warn_unreachable_return;
1000b57cec5SDimitry Andric           break;
1010b57cec5SDimitry Andric         case reachable_code::UK_Loop_Increment:
1020b57cec5SDimitry Andric           diag = diag::warn_unreachable_loop_increment;
1030b57cec5SDimitry Andric           break;
1040b57cec5SDimitry Andric         case reachable_code::UK_Other:
1050b57cec5SDimitry Andric           break;
1060b57cec5SDimitry Andric       }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric       S.Diag(L, diag) << R1 << R2;
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric       SourceLocation Open = SilenceableCondVal.getBegin();
1110b57cec5SDimitry Andric       if (Open.isValid()) {
1120b57cec5SDimitry Andric         SourceLocation Close = SilenceableCondVal.getEnd();
1130b57cec5SDimitry Andric         Close = S.getLocForEndOfToken(Close);
1140b57cec5SDimitry Andric         if (Close.isValid()) {
1150b57cec5SDimitry Andric           S.Diag(Open, diag::note_unreachable_silence)
1160b57cec5SDimitry Andric             << FixItHint::CreateInsertion(Open, "/* DISABLES CODE */ (")
1170b57cec5SDimitry Andric             << FixItHint::CreateInsertion(Close, ")");
1180b57cec5SDimitry Andric         }
1190b57cec5SDimitry Andric       }
1200b57cec5SDimitry Andric     }
1210b57cec5SDimitry Andric   };
1220b57cec5SDimitry Andric } // anonymous namespace
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric /// CheckUnreachable - Check for unreachable code.
CheckUnreachable(Sema & S,AnalysisDeclContext & AC)1250b57cec5SDimitry Andric static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC) {
1260b57cec5SDimitry Andric   // As a heuristic prune all diagnostics not in the main file.  Currently
1270b57cec5SDimitry Andric   // the majority of warnings in headers are false positives.  These
1280b57cec5SDimitry Andric   // are largely caused by configuration state, e.g. preprocessor
1290b57cec5SDimitry Andric   // defined code, etc.
1300b57cec5SDimitry Andric   //
1310b57cec5SDimitry Andric   // Note that this is also a performance optimization.  Analyzing
1320b57cec5SDimitry Andric   // headers many times can be expensive.
1330b57cec5SDimitry Andric   if (!S.getSourceManager().isInMainFile(AC.getDecl()->getBeginLoc()))
1340b57cec5SDimitry Andric     return;
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric   UnreachableCodeHandler UC(S);
1370b57cec5SDimitry Andric   reachable_code::FindUnreachableCode(AC, S.getPreprocessor(), UC);
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric namespace {
1410b57cec5SDimitry Andric /// Warn on logical operator errors in CFGBuilder
1420b57cec5SDimitry Andric class LogicalErrorHandler : public CFGCallback {
1430b57cec5SDimitry Andric   Sema &S;
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric public:
LogicalErrorHandler(Sema & S)14604eeddc0SDimitry Andric   LogicalErrorHandler(Sema &S) : S(S) {}
1470b57cec5SDimitry Andric 
HasMacroID(const Expr * E)1480b57cec5SDimitry Andric   static bool HasMacroID(const Expr *E) {
1490b57cec5SDimitry Andric     if (E->getExprLoc().isMacroID())
1500b57cec5SDimitry Andric       return true;
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric     // Recurse to children.
1530b57cec5SDimitry Andric     for (const Stmt *SubStmt : E->children())
1540b57cec5SDimitry Andric       if (const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt))
1550b57cec5SDimitry Andric         if (HasMacroID(SubExpr))
1560b57cec5SDimitry Andric           return true;
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric     return false;
1590b57cec5SDimitry Andric   }
1600b57cec5SDimitry Andric 
logicAlwaysTrue(const BinaryOperator * B,bool isAlwaysTrue)1615f757f3fSDimitry Andric   void logicAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) override {
1625f757f3fSDimitry Andric     if (HasMacroID(B))
1635f757f3fSDimitry Andric       return;
1645f757f3fSDimitry Andric 
1655f757f3fSDimitry Andric     unsigned DiagID = isAlwaysTrue
1665f757f3fSDimitry Andric                           ? diag::warn_tautological_negation_or_compare
1675f757f3fSDimitry Andric                           : diag::warn_tautological_negation_and_compare;
1685f757f3fSDimitry Andric     SourceRange DiagRange = B->getSourceRange();
1695f757f3fSDimitry Andric     S.Diag(B->getExprLoc(), DiagID) << DiagRange;
1705f757f3fSDimitry Andric   }
1715f757f3fSDimitry Andric 
compareAlwaysTrue(const BinaryOperator * B,bool isAlwaysTrue)1720b57cec5SDimitry Andric   void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) override {
1730b57cec5SDimitry Andric     if (HasMacroID(B))
1740b57cec5SDimitry Andric       return;
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric     SourceRange DiagRange = B->getSourceRange();
1770b57cec5SDimitry Andric     S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison)
1780b57cec5SDimitry Andric         << DiagRange << isAlwaysTrue;
1790b57cec5SDimitry Andric   }
1800b57cec5SDimitry Andric 
compareBitwiseEquality(const BinaryOperator * B,bool isAlwaysTrue)1810b57cec5SDimitry Andric   void compareBitwiseEquality(const BinaryOperator *B,
1820b57cec5SDimitry Andric                               bool isAlwaysTrue) override {
1830b57cec5SDimitry Andric     if (HasMacroID(B))
1840b57cec5SDimitry Andric       return;
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric     SourceRange DiagRange = B->getSourceRange();
1870b57cec5SDimitry Andric     S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_always)
1880b57cec5SDimitry Andric         << DiagRange << isAlwaysTrue;
1890b57cec5SDimitry Andric   }
190a7dea167SDimitry Andric 
compareBitwiseOr(const BinaryOperator * B)191a7dea167SDimitry Andric   void compareBitwiseOr(const BinaryOperator *B) override {
192a7dea167SDimitry Andric     if (HasMacroID(B))
193a7dea167SDimitry Andric       return;
194a7dea167SDimitry Andric 
195a7dea167SDimitry Andric     SourceRange DiagRange = B->getSourceRange();
196a7dea167SDimitry Andric     S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;
197a7dea167SDimitry Andric   }
198a7dea167SDimitry Andric 
hasActiveDiagnostics(DiagnosticsEngine & Diags,SourceLocation Loc)199a7dea167SDimitry Andric   static bool hasActiveDiagnostics(DiagnosticsEngine &Diags,
200a7dea167SDimitry Andric                                    SourceLocation Loc) {
201a7dea167SDimitry Andric     return !Diags.isIgnored(diag::warn_tautological_overlap_comparison, Loc) ||
2025f757f3fSDimitry Andric            !Diags.isIgnored(diag::warn_comparison_bitwise_or, Loc) ||
2035f757f3fSDimitry Andric            !Diags.isIgnored(diag::warn_tautological_negation_and_compare, Loc);
204a7dea167SDimitry Andric   }
2050b57cec5SDimitry Andric };
2060b57cec5SDimitry Andric } // anonymous namespace
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2090b57cec5SDimitry Andric // Check for infinite self-recursion in functions
2100b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric // Returns true if the function is called anywhere within the CFGBlock.
2130b57cec5SDimitry Andric // For member functions, the additional condition of being call from the
2140b57cec5SDimitry Andric // this pointer is required.
hasRecursiveCallInPath(const FunctionDecl * FD,CFGBlock & Block)2150b57cec5SDimitry Andric static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block) {
2160b57cec5SDimitry Andric   // Process all the Stmt's in this block to find any calls to FD.
2170b57cec5SDimitry Andric   for (const auto &B : Block) {
2180b57cec5SDimitry Andric     if (B.getKind() != CFGElement::Statement)
2190b57cec5SDimitry Andric       continue;
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric     const CallExpr *CE = dyn_cast<CallExpr>(B.getAs<CFGStmt>()->getStmt());
2220b57cec5SDimitry Andric     if (!CE || !CE->getCalleeDecl() ||
2230b57cec5SDimitry Andric         CE->getCalleeDecl()->getCanonicalDecl() != FD)
2240b57cec5SDimitry Andric       continue;
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric     // Skip function calls which are qualified with a templated class.
2270b57cec5SDimitry Andric     if (const DeclRefExpr *DRE =
2280b57cec5SDimitry Andric             dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenImpCasts())) {
2290b57cec5SDimitry Andric       if (NestedNameSpecifier *NNS = DRE->getQualifier()) {
2300b57cec5SDimitry Andric         if (NNS->getKind() == NestedNameSpecifier::TypeSpec &&
2310b57cec5SDimitry Andric             isa<TemplateSpecializationType>(NNS->getAsType())) {
2320b57cec5SDimitry Andric           continue;
2330b57cec5SDimitry Andric         }
2340b57cec5SDimitry Andric       }
2350b57cec5SDimitry Andric     }
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric     const CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(CE);
2380b57cec5SDimitry Andric     if (!MCE || isa<CXXThisExpr>(MCE->getImplicitObjectArgument()) ||
2390b57cec5SDimitry Andric         !MCE->getMethodDecl()->isVirtual())
2400b57cec5SDimitry Andric       return true;
2410b57cec5SDimitry Andric   }
2420b57cec5SDimitry Andric   return false;
2430b57cec5SDimitry Andric }
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric // Returns true if every path from the entry block passes through a call to FD.
checkForRecursiveFunctionCall(const FunctionDecl * FD,CFG * cfg)2460b57cec5SDimitry Andric static bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg) {
2470b57cec5SDimitry Andric   llvm::SmallPtrSet<CFGBlock *, 16> Visited;
2480b57cec5SDimitry Andric   llvm::SmallVector<CFGBlock *, 16> WorkList;
2490b57cec5SDimitry Andric   // Keep track of whether we found at least one recursive path.
2500b57cec5SDimitry Andric   bool foundRecursion = false;
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric   const unsigned ExitID = cfg->getExit().getBlockID();
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric   // Seed the work list with the entry block.
2550b57cec5SDimitry Andric   WorkList.push_back(&cfg->getEntry());
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   while (!WorkList.empty()) {
2580b57cec5SDimitry Andric     CFGBlock *Block = WorkList.pop_back_val();
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric     for (auto I = Block->succ_begin(), E = Block->succ_end(); I != E; ++I) {
2610b57cec5SDimitry Andric       if (CFGBlock *SuccBlock = *I) {
2620b57cec5SDimitry Andric         if (!Visited.insert(SuccBlock).second)
2630b57cec5SDimitry Andric           continue;
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric         // Found a path to the exit node without a recursive call.
2660b57cec5SDimitry Andric         if (ExitID == SuccBlock->getBlockID())
2670b57cec5SDimitry Andric           return false;
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric         // If the successor block contains a recursive call, end analysis there.
2700b57cec5SDimitry Andric         if (hasRecursiveCallInPath(FD, *SuccBlock)) {
2710b57cec5SDimitry Andric           foundRecursion = true;
2720b57cec5SDimitry Andric           continue;
2730b57cec5SDimitry Andric         }
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric         WorkList.push_back(SuccBlock);
2760b57cec5SDimitry Andric       }
2770b57cec5SDimitry Andric     }
2780b57cec5SDimitry Andric   }
2790b57cec5SDimitry Andric   return foundRecursion;
2800b57cec5SDimitry Andric }
2810b57cec5SDimitry Andric 
checkRecursiveFunction(Sema & S,const FunctionDecl * FD,const Stmt * Body,AnalysisDeclContext & AC)2820b57cec5SDimitry Andric static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,
2830b57cec5SDimitry Andric                                    const Stmt *Body, AnalysisDeclContext &AC) {
2840b57cec5SDimitry Andric   FD = FD->getCanonicalDecl();
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   // Only run on non-templated functions and non-templated members of
2870b57cec5SDimitry Andric   // templated classes.
2880b57cec5SDimitry Andric   if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate &&
2890b57cec5SDimitry Andric       FD->getTemplatedKind() != FunctionDecl::TK_MemberSpecialization)
2900b57cec5SDimitry Andric     return;
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric   CFG *cfg = AC.getCFG();
2930b57cec5SDimitry Andric   if (!cfg) return;
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric   // If the exit block is unreachable, skip processing the function.
2960b57cec5SDimitry Andric   if (cfg->getExit().pred_empty())
2970b57cec5SDimitry Andric     return;
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric   // Emit diagnostic if a recursive function call is detected for all paths.
3000b57cec5SDimitry Andric   if (checkForRecursiveFunctionCall(FD, cfg))
3010b57cec5SDimitry Andric     S.Diag(Body->getBeginLoc(), diag::warn_infinite_recursive_function);
3020b57cec5SDimitry Andric }
3030b57cec5SDimitry Andric 
3040b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3050b57cec5SDimitry Andric // Check for throw in a non-throwing function.
3060b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric /// Determine whether an exception thrown by E, unwinding from ThrowBlock,
3090b57cec5SDimitry Andric /// can reach ExitBlock.
throwEscapes(Sema & S,const CXXThrowExpr * E,CFGBlock & ThrowBlock,CFG * Body)3100b57cec5SDimitry Andric static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock,
3110b57cec5SDimitry Andric                          CFG *Body) {
3120b57cec5SDimitry Andric   SmallVector<CFGBlock *, 16> Stack;
3130b57cec5SDimitry Andric   llvm::BitVector Queued(Body->getNumBlockIDs());
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric   Stack.push_back(&ThrowBlock);
3160b57cec5SDimitry Andric   Queued[ThrowBlock.getBlockID()] = true;
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric   while (!Stack.empty()) {
3190b57cec5SDimitry Andric     CFGBlock &UnwindBlock = *Stack.back();
3200b57cec5SDimitry Andric     Stack.pop_back();
3210b57cec5SDimitry Andric 
3220b57cec5SDimitry Andric     for (auto &Succ : UnwindBlock.succs()) {
3230b57cec5SDimitry Andric       if (!Succ.isReachable() || Queued[Succ->getBlockID()])
3240b57cec5SDimitry Andric         continue;
3250b57cec5SDimitry Andric 
3260b57cec5SDimitry Andric       if (Succ->getBlockID() == Body->getExit().getBlockID())
3270b57cec5SDimitry Andric         return true;
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric       if (auto *Catch =
3300b57cec5SDimitry Andric               dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
3310b57cec5SDimitry Andric         QualType Caught = Catch->getCaughtType();
3320b57cec5SDimitry Andric         if (Caught.isNull() || // catch (...) catches everything
3330b57cec5SDimitry Andric             !E->getSubExpr() || // throw; is considered cuaght by any handler
3340b57cec5SDimitry Andric             S.handlerCanCatch(Caught, E->getSubExpr()->getType()))
3350b57cec5SDimitry Andric           // Exception doesn't escape via this path.
3360b57cec5SDimitry Andric           break;
3370b57cec5SDimitry Andric       } else {
3380b57cec5SDimitry Andric         Stack.push_back(Succ);
3390b57cec5SDimitry Andric         Queued[Succ->getBlockID()] = true;
3400b57cec5SDimitry Andric       }
3410b57cec5SDimitry Andric     }
3420b57cec5SDimitry Andric   }
3430b57cec5SDimitry Andric 
3440b57cec5SDimitry Andric   return false;
3450b57cec5SDimitry Andric }
3460b57cec5SDimitry Andric 
visitReachableThrows(CFG * BodyCFG,llvm::function_ref<void (const CXXThrowExpr *,CFGBlock &)> Visit)3470b57cec5SDimitry Andric static void visitReachableThrows(
3480b57cec5SDimitry Andric     CFG *BodyCFG,
3490b57cec5SDimitry Andric     llvm::function_ref<void(const CXXThrowExpr *, CFGBlock &)> Visit) {
3500b57cec5SDimitry Andric   llvm::BitVector Reachable(BodyCFG->getNumBlockIDs());
3510b57cec5SDimitry Andric   clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(), Reachable);
3520b57cec5SDimitry Andric   for (CFGBlock *B : *BodyCFG) {
3530b57cec5SDimitry Andric     if (!Reachable[B->getBlockID()])
3540b57cec5SDimitry Andric       continue;
3550b57cec5SDimitry Andric     for (CFGElement &E : *B) {
356bdd1243dSDimitry Andric       std::optional<CFGStmt> S = E.getAs<CFGStmt>();
3570b57cec5SDimitry Andric       if (!S)
3580b57cec5SDimitry Andric         continue;
3590b57cec5SDimitry Andric       if (auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))
3600b57cec5SDimitry Andric         Visit(Throw, *B);
3610b57cec5SDimitry Andric     }
3620b57cec5SDimitry Andric   }
3630b57cec5SDimitry Andric }
3640b57cec5SDimitry Andric 
EmitDiagForCXXThrowInNonThrowingFunc(Sema & S,SourceLocation OpLoc,const FunctionDecl * FD)3650b57cec5SDimitry Andric static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc,
3660b57cec5SDimitry Andric                                                  const FunctionDecl *FD) {
3670b57cec5SDimitry Andric   if (!S.getSourceManager().isInSystemHeader(OpLoc) &&
3680b57cec5SDimitry Andric       FD->getTypeSourceInfo()) {
3690b57cec5SDimitry Andric     S.Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
3700b57cec5SDimitry Andric     if (S.getLangOpts().CPlusPlus11 &&
3710b57cec5SDimitry Andric         (isa<CXXDestructorDecl>(FD) ||
3720b57cec5SDimitry Andric          FD->getDeclName().getCXXOverloadedOperator() == OO_Delete ||
3730b57cec5SDimitry Andric          FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) {
3740b57cec5SDimitry Andric       if (const auto *Ty = FD->getTypeSourceInfo()->getType()->
3750b57cec5SDimitry Andric                                          getAs<FunctionProtoType>())
3760b57cec5SDimitry Andric         S.Diag(FD->getLocation(), diag::note_throw_in_dtor)
3770b57cec5SDimitry Andric             << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec()
3780b57cec5SDimitry Andric             << FD->getExceptionSpecSourceRange();
3790b57cec5SDimitry Andric     } else
3800b57cec5SDimitry Andric       S.Diag(FD->getLocation(), diag::note_throw_in_function)
3810b57cec5SDimitry Andric           << FD->getExceptionSpecSourceRange();
3820b57cec5SDimitry Andric   }
3830b57cec5SDimitry Andric }
3840b57cec5SDimitry Andric 
checkThrowInNonThrowingFunc(Sema & S,const FunctionDecl * FD,AnalysisDeclContext & AC)3850b57cec5SDimitry Andric static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD,
3860b57cec5SDimitry Andric                                         AnalysisDeclContext &AC) {
3870b57cec5SDimitry Andric   CFG *BodyCFG = AC.getCFG();
3880b57cec5SDimitry Andric   if (!BodyCFG)
3890b57cec5SDimitry Andric     return;
3900b57cec5SDimitry Andric   if (BodyCFG->getExit().pred_empty())
3910b57cec5SDimitry Andric     return;
3920b57cec5SDimitry Andric   visitReachableThrows(BodyCFG, [&](const CXXThrowExpr *Throw, CFGBlock &Block) {
3930b57cec5SDimitry Andric     if (throwEscapes(S, Throw, Block, BodyCFG))
3940b57cec5SDimitry Andric       EmitDiagForCXXThrowInNonThrowingFunc(S, Throw->getThrowLoc(), FD);
3950b57cec5SDimitry Andric   });
3960b57cec5SDimitry Andric }
3970b57cec5SDimitry Andric 
isNoexcept(const FunctionDecl * FD)3980b57cec5SDimitry Andric static bool isNoexcept(const FunctionDecl *FD) {
3990b57cec5SDimitry Andric   const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
4000b57cec5SDimitry Andric   if (FPT->isNothrow() || FD->hasAttr<NoThrowAttr>())
4010b57cec5SDimitry Andric     return true;
4020b57cec5SDimitry Andric   return false;
4030b57cec5SDimitry Andric }
4040b57cec5SDimitry Andric 
4050b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4060b57cec5SDimitry Andric // Check for missing return value.
4070b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric enum ControlFlowKind {
4100b57cec5SDimitry Andric   UnknownFallThrough,
4110b57cec5SDimitry Andric   NeverFallThrough,
4120b57cec5SDimitry Andric   MaybeFallThrough,
4130b57cec5SDimitry Andric   AlwaysFallThrough,
4140b57cec5SDimitry Andric   NeverFallThroughOrReturn
4150b57cec5SDimitry Andric };
4160b57cec5SDimitry Andric 
4170b57cec5SDimitry Andric /// CheckFallThrough - Check that we don't fall off the end of a
4180b57cec5SDimitry Andric /// Statement that should return a value.
4190b57cec5SDimitry Andric ///
4200b57cec5SDimitry Andric /// \returns AlwaysFallThrough iff we always fall off the end of the statement,
4210b57cec5SDimitry Andric /// MaybeFallThrough iff we might or might not fall off the end,
4220b57cec5SDimitry Andric /// NeverFallThroughOrReturn iff we never fall off the end of the statement or
4230b57cec5SDimitry Andric /// return.  We assume NeverFallThrough iff we never fall off the end of the
4240b57cec5SDimitry Andric /// statement but we may return.  We assume that functions not marked noreturn
4250b57cec5SDimitry Andric /// will return.
CheckFallThrough(AnalysisDeclContext & AC)4260b57cec5SDimitry Andric static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
4270b57cec5SDimitry Andric   CFG *cfg = AC.getCFG();
4280b57cec5SDimitry Andric   if (!cfg) return UnknownFallThrough;
4290b57cec5SDimitry Andric 
4300b57cec5SDimitry Andric   // The CFG leaves in dead things, and we don't want the dead code paths to
4310b57cec5SDimitry Andric   // confuse us, so we mark all live things first.
4320b57cec5SDimitry Andric   llvm::BitVector live(cfg->getNumBlockIDs());
4330b57cec5SDimitry Andric   unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(),
4340b57cec5SDimitry Andric                                                           live);
4350b57cec5SDimitry Andric 
4360b57cec5SDimitry Andric   bool AddEHEdges = AC.getAddEHEdges();
4370b57cec5SDimitry Andric   if (!AddEHEdges && count != cfg->getNumBlockIDs())
4380b57cec5SDimitry Andric     // When there are things remaining dead, and we didn't add EH edges
4390b57cec5SDimitry Andric     // from CallExprs to the catch clauses, we have to go back and
4400b57cec5SDimitry Andric     // mark them as live.
4410b57cec5SDimitry Andric     for (const auto *B : *cfg) {
4420b57cec5SDimitry Andric       if (!live[B->getBlockID()]) {
4430b57cec5SDimitry Andric         if (B->pred_begin() == B->pred_end()) {
4440b57cec5SDimitry Andric           const Stmt *Term = B->getTerminatorStmt();
445*0fca6ea1SDimitry Andric           if (isa_and_nonnull<CXXTryStmt>(Term))
4460b57cec5SDimitry Andric             // When not adding EH edges from calls, catch clauses
4470b57cec5SDimitry Andric             // can otherwise seem dead.  Avoid noting them as dead.
4480b57cec5SDimitry Andric             count += reachable_code::ScanReachableFromBlock(B, live);
4490b57cec5SDimitry Andric           continue;
4500b57cec5SDimitry Andric         }
4510b57cec5SDimitry Andric       }
4520b57cec5SDimitry Andric     }
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric   // Now we know what is live, we check the live precessors of the exit block
4550b57cec5SDimitry Andric   // and look for fall through paths, being careful to ignore normal returns,
4560b57cec5SDimitry Andric   // and exceptional paths.
4570b57cec5SDimitry Andric   bool HasLiveReturn = false;
4580b57cec5SDimitry Andric   bool HasFakeEdge = false;
4590b57cec5SDimitry Andric   bool HasPlainEdge = false;
4600b57cec5SDimitry Andric   bool HasAbnormalEdge = false;
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric   // Ignore default cases that aren't likely to be reachable because all
4630b57cec5SDimitry Andric   // enums in a switch(X) have explicit case statements.
4640b57cec5SDimitry Andric   CFGBlock::FilterOptions FO;
4650b57cec5SDimitry Andric   FO.IgnoreDefaultsWithCoveredEnums = 1;
4660b57cec5SDimitry Andric 
4670b57cec5SDimitry Andric   for (CFGBlock::filtered_pred_iterator I =
4680b57cec5SDimitry Andric            cfg->getExit().filtered_pred_start_end(FO);
4690b57cec5SDimitry Andric        I.hasMore(); ++I) {
4700b57cec5SDimitry Andric     const CFGBlock &B = **I;
4710b57cec5SDimitry Andric     if (!live[B.getBlockID()])
4720b57cec5SDimitry Andric       continue;
4730b57cec5SDimitry Andric 
4740b57cec5SDimitry Andric     // Skip blocks which contain an element marked as no-return. They don't
4750b57cec5SDimitry Andric     // represent actually viable edges into the exit block, so mark them as
4760b57cec5SDimitry Andric     // abnormal.
4770b57cec5SDimitry Andric     if (B.hasNoReturnElement()) {
4780b57cec5SDimitry Andric       HasAbnormalEdge = true;
4790b57cec5SDimitry Andric       continue;
4800b57cec5SDimitry Andric     }
4810b57cec5SDimitry Andric 
4820b57cec5SDimitry Andric     // Destructors can appear after the 'return' in the CFG.  This is
4830b57cec5SDimitry Andric     // normal.  We need to look pass the destructors for the return
4840b57cec5SDimitry Andric     // statement (if it exists).
4850b57cec5SDimitry Andric     CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend();
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric     for ( ; ri != re ; ++ri)
4880b57cec5SDimitry Andric       if (ri->getAs<CFGStmt>())
4890b57cec5SDimitry Andric         break;
4900b57cec5SDimitry Andric 
4910b57cec5SDimitry Andric     // No more CFGElements in the block?
4920b57cec5SDimitry Andric     if (ri == re) {
4930b57cec5SDimitry Andric       const Stmt *Term = B.getTerminatorStmt();
4944824e7fdSDimitry Andric       if (Term && (isa<CXXTryStmt>(Term) || isa<ObjCAtTryStmt>(Term))) {
4950b57cec5SDimitry Andric         HasAbnormalEdge = true;
4960b57cec5SDimitry Andric         continue;
4970b57cec5SDimitry Andric       }
4980b57cec5SDimitry Andric       // A labeled empty statement, or the entry block...
4990b57cec5SDimitry Andric       HasPlainEdge = true;
5000b57cec5SDimitry Andric       continue;
5010b57cec5SDimitry Andric     }
5020b57cec5SDimitry Andric 
5030b57cec5SDimitry Andric     CFGStmt CS = ri->castAs<CFGStmt>();
5040b57cec5SDimitry Andric     const Stmt *S = CS.getStmt();
5050b57cec5SDimitry Andric     if (isa<ReturnStmt>(S) || isa<CoreturnStmt>(S)) {
5060b57cec5SDimitry Andric       HasLiveReturn = true;
5070b57cec5SDimitry Andric       continue;
5080b57cec5SDimitry Andric     }
5090b57cec5SDimitry Andric     if (isa<ObjCAtThrowStmt>(S)) {
5100b57cec5SDimitry Andric       HasFakeEdge = true;
5110b57cec5SDimitry Andric       continue;
5120b57cec5SDimitry Andric     }
5130b57cec5SDimitry Andric     if (isa<CXXThrowExpr>(S)) {
5140b57cec5SDimitry Andric       HasFakeEdge = true;
5150b57cec5SDimitry Andric       continue;
5160b57cec5SDimitry Andric     }
5170b57cec5SDimitry Andric     if (isa<MSAsmStmt>(S)) {
5180b57cec5SDimitry Andric       // TODO: Verify this is correct.
5190b57cec5SDimitry Andric       HasFakeEdge = true;
5200b57cec5SDimitry Andric       HasLiveReturn = true;
5210b57cec5SDimitry Andric       continue;
5220b57cec5SDimitry Andric     }
5230b57cec5SDimitry Andric     if (isa<CXXTryStmt>(S)) {
5240b57cec5SDimitry Andric       HasAbnormalEdge = true;
5250b57cec5SDimitry Andric       continue;
5260b57cec5SDimitry Andric     }
527349cc55cSDimitry Andric     if (!llvm::is_contained(B.succs(), &cfg->getExit())) {
5280b57cec5SDimitry Andric       HasAbnormalEdge = true;
5290b57cec5SDimitry Andric       continue;
5300b57cec5SDimitry Andric     }
5310b57cec5SDimitry Andric 
5320b57cec5SDimitry Andric     HasPlainEdge = true;
5330b57cec5SDimitry Andric   }
5340b57cec5SDimitry Andric   if (!HasPlainEdge) {
5350b57cec5SDimitry Andric     if (HasLiveReturn)
5360b57cec5SDimitry Andric       return NeverFallThrough;
5370b57cec5SDimitry Andric     return NeverFallThroughOrReturn;
5380b57cec5SDimitry Andric   }
5390b57cec5SDimitry Andric   if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
5400b57cec5SDimitry Andric     return MaybeFallThrough;
5410b57cec5SDimitry Andric   // This says AlwaysFallThrough for calls to functions that are not marked
5420b57cec5SDimitry Andric   // noreturn, that don't return.  If people would like this warning to be more
5430b57cec5SDimitry Andric   // accurate, such functions should be marked as noreturn.
5440b57cec5SDimitry Andric   return AlwaysFallThrough;
5450b57cec5SDimitry Andric }
5460b57cec5SDimitry Andric 
5470b57cec5SDimitry Andric namespace {
5480b57cec5SDimitry Andric 
5490b57cec5SDimitry Andric struct CheckFallThroughDiagnostics {
5500b57cec5SDimitry Andric   unsigned diag_MaybeFallThrough_HasNoReturn;
5510b57cec5SDimitry Andric   unsigned diag_MaybeFallThrough_ReturnsNonVoid;
5520b57cec5SDimitry Andric   unsigned diag_AlwaysFallThrough_HasNoReturn;
5530b57cec5SDimitry Andric   unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
5540b57cec5SDimitry Andric   unsigned diag_NeverFallThroughOrReturn;
5550b57cec5SDimitry Andric   enum { Function, Block, Lambda, Coroutine } funMode;
5560b57cec5SDimitry Andric   SourceLocation FuncLoc;
5570b57cec5SDimitry Andric 
MakeForFunction__anon9476153b0411::CheckFallThroughDiagnostics5580b57cec5SDimitry Andric   static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) {
5590b57cec5SDimitry Andric     CheckFallThroughDiagnostics D;
5600b57cec5SDimitry Andric     D.FuncLoc = Func->getLocation();
5610b57cec5SDimitry Andric     D.diag_MaybeFallThrough_HasNoReturn =
5620b57cec5SDimitry Andric       diag::warn_falloff_noreturn_function;
5630b57cec5SDimitry Andric     D.diag_MaybeFallThrough_ReturnsNonVoid =
5640b57cec5SDimitry Andric       diag::warn_maybe_falloff_nonvoid_function;
5650b57cec5SDimitry Andric     D.diag_AlwaysFallThrough_HasNoReturn =
5660b57cec5SDimitry Andric       diag::warn_falloff_noreturn_function;
5670b57cec5SDimitry Andric     D.diag_AlwaysFallThrough_ReturnsNonVoid =
5680b57cec5SDimitry Andric       diag::warn_falloff_nonvoid_function;
5690b57cec5SDimitry Andric 
5700b57cec5SDimitry Andric     // Don't suggest that virtual functions be marked "noreturn", since they
5710b57cec5SDimitry Andric     // might be overridden by non-noreturn functions.
5720b57cec5SDimitry Andric     bool isVirtualMethod = false;
5730b57cec5SDimitry Andric     if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func))
5740b57cec5SDimitry Andric       isVirtualMethod = Method->isVirtual();
5750b57cec5SDimitry Andric 
5760b57cec5SDimitry Andric     // Don't suggest that template instantiations be marked "noreturn"
5770b57cec5SDimitry Andric     bool isTemplateInstantiation = false;
5780b57cec5SDimitry Andric     if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func))
5790b57cec5SDimitry Andric       isTemplateInstantiation = Function->isTemplateInstantiation();
5800b57cec5SDimitry Andric 
5810b57cec5SDimitry Andric     if (!isVirtualMethod && !isTemplateInstantiation)
5820b57cec5SDimitry Andric       D.diag_NeverFallThroughOrReturn =
5830b57cec5SDimitry Andric         diag::warn_suggest_noreturn_function;
5840b57cec5SDimitry Andric     else
5850b57cec5SDimitry Andric       D.diag_NeverFallThroughOrReturn = 0;
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric     D.funMode = Function;
5880b57cec5SDimitry Andric     return D;
5890b57cec5SDimitry Andric   }
5900b57cec5SDimitry Andric 
MakeForCoroutine__anon9476153b0411::CheckFallThroughDiagnostics5910b57cec5SDimitry Andric   static CheckFallThroughDiagnostics MakeForCoroutine(const Decl *Func) {
5920b57cec5SDimitry Andric     CheckFallThroughDiagnostics D;
5930b57cec5SDimitry Andric     D.FuncLoc = Func->getLocation();
5940b57cec5SDimitry Andric     D.diag_MaybeFallThrough_HasNoReturn = 0;
5950b57cec5SDimitry Andric     D.diag_MaybeFallThrough_ReturnsNonVoid =
5960b57cec5SDimitry Andric         diag::warn_maybe_falloff_nonvoid_coroutine;
5970b57cec5SDimitry Andric     D.diag_AlwaysFallThrough_HasNoReturn = 0;
5980b57cec5SDimitry Andric     D.diag_AlwaysFallThrough_ReturnsNonVoid =
5990b57cec5SDimitry Andric         diag::warn_falloff_nonvoid_coroutine;
60006c3fb27SDimitry Andric     D.diag_NeverFallThroughOrReturn = 0;
6010b57cec5SDimitry Andric     D.funMode = Coroutine;
6020b57cec5SDimitry Andric     return D;
6030b57cec5SDimitry Andric   }
6040b57cec5SDimitry Andric 
MakeForBlock__anon9476153b0411::CheckFallThroughDiagnostics6050b57cec5SDimitry Andric   static CheckFallThroughDiagnostics MakeForBlock() {
6060b57cec5SDimitry Andric     CheckFallThroughDiagnostics D;
6070b57cec5SDimitry Andric     D.diag_MaybeFallThrough_HasNoReturn =
6080b57cec5SDimitry Andric       diag::err_noreturn_block_has_return_expr;
6090b57cec5SDimitry Andric     D.diag_MaybeFallThrough_ReturnsNonVoid =
6100b57cec5SDimitry Andric       diag::err_maybe_falloff_nonvoid_block;
6110b57cec5SDimitry Andric     D.diag_AlwaysFallThrough_HasNoReturn =
6120b57cec5SDimitry Andric       diag::err_noreturn_block_has_return_expr;
6130b57cec5SDimitry Andric     D.diag_AlwaysFallThrough_ReturnsNonVoid =
6140b57cec5SDimitry Andric       diag::err_falloff_nonvoid_block;
6150b57cec5SDimitry Andric     D.diag_NeverFallThroughOrReturn = 0;
6160b57cec5SDimitry Andric     D.funMode = Block;
6170b57cec5SDimitry Andric     return D;
6180b57cec5SDimitry Andric   }
6190b57cec5SDimitry Andric 
MakeForLambda__anon9476153b0411::CheckFallThroughDiagnostics6200b57cec5SDimitry Andric   static CheckFallThroughDiagnostics MakeForLambda() {
6210b57cec5SDimitry Andric     CheckFallThroughDiagnostics D;
6220b57cec5SDimitry Andric     D.diag_MaybeFallThrough_HasNoReturn =
6230b57cec5SDimitry Andric       diag::err_noreturn_lambda_has_return_expr;
6240b57cec5SDimitry Andric     D.diag_MaybeFallThrough_ReturnsNonVoid =
6250b57cec5SDimitry Andric       diag::warn_maybe_falloff_nonvoid_lambda;
6260b57cec5SDimitry Andric     D.diag_AlwaysFallThrough_HasNoReturn =
6270b57cec5SDimitry Andric       diag::err_noreturn_lambda_has_return_expr;
6280b57cec5SDimitry Andric     D.diag_AlwaysFallThrough_ReturnsNonVoid =
6290b57cec5SDimitry Andric       diag::warn_falloff_nonvoid_lambda;
6300b57cec5SDimitry Andric     D.diag_NeverFallThroughOrReturn = 0;
6310b57cec5SDimitry Andric     D.funMode = Lambda;
6320b57cec5SDimitry Andric     return D;
6330b57cec5SDimitry Andric   }
6340b57cec5SDimitry Andric 
checkDiagnostics__anon9476153b0411::CheckFallThroughDiagnostics6350b57cec5SDimitry Andric   bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid,
6360b57cec5SDimitry Andric                         bool HasNoReturn) const {
6370b57cec5SDimitry Andric     if (funMode == Function) {
6380b57cec5SDimitry Andric       return (ReturnsVoid ||
6390b57cec5SDimitry Andric               D.isIgnored(diag::warn_maybe_falloff_nonvoid_function,
6400b57cec5SDimitry Andric                           FuncLoc)) &&
6410b57cec5SDimitry Andric              (!HasNoReturn ||
6420b57cec5SDimitry Andric               D.isIgnored(diag::warn_noreturn_function_has_return_expr,
6430b57cec5SDimitry Andric                           FuncLoc)) &&
6440b57cec5SDimitry Andric              (!ReturnsVoid ||
6450b57cec5SDimitry Andric               D.isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));
6460b57cec5SDimitry Andric     }
6470b57cec5SDimitry Andric     if (funMode == Coroutine) {
6480b57cec5SDimitry Andric       return (ReturnsVoid ||
6490b57cec5SDimitry Andric               D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, FuncLoc) ||
6500b57cec5SDimitry Andric               D.isIgnored(diag::warn_maybe_falloff_nonvoid_coroutine,
6510b57cec5SDimitry Andric                           FuncLoc)) &&
6520b57cec5SDimitry Andric              (!HasNoReturn);
6530b57cec5SDimitry Andric     }
6540b57cec5SDimitry Andric     // For blocks / lambdas.
6550b57cec5SDimitry Andric     return ReturnsVoid && !HasNoReturn;
6560b57cec5SDimitry Andric   }
6570b57cec5SDimitry Andric };
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric } // anonymous namespace
6600b57cec5SDimitry Andric 
6610b57cec5SDimitry Andric /// CheckFallThroughForBody - Check that we don't fall off the end of a
6620b57cec5SDimitry Andric /// function that should return a value.  Check that we don't fall off the end
6630b57cec5SDimitry Andric /// of a noreturn function.  We assume that functions and blocks not marked
6640b57cec5SDimitry Andric /// noreturn will return.
CheckFallThroughForBody(Sema & S,const Decl * D,const Stmt * Body,QualType BlockType,const CheckFallThroughDiagnostics & CD,AnalysisDeclContext & AC,sema::FunctionScopeInfo * FSI)6650b57cec5SDimitry Andric static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
6660b57cec5SDimitry Andric                                     QualType BlockType,
6670b57cec5SDimitry Andric                                     const CheckFallThroughDiagnostics &CD,
6680b57cec5SDimitry Andric                                     AnalysisDeclContext &AC,
6690b57cec5SDimitry Andric                                     sema::FunctionScopeInfo *FSI) {
6700b57cec5SDimitry Andric 
6710b57cec5SDimitry Andric   bool ReturnsVoid = false;
6720b57cec5SDimitry Andric   bool HasNoReturn = false;
6730b57cec5SDimitry Andric   bool IsCoroutine = FSI->isCoroutine();
6740b57cec5SDimitry Andric 
6750b57cec5SDimitry Andric   if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
6760b57cec5SDimitry Andric     if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
6770b57cec5SDimitry Andric       ReturnsVoid = CBody->getFallthroughHandler() != nullptr;
6780b57cec5SDimitry Andric     else
6790b57cec5SDimitry Andric       ReturnsVoid = FD->getReturnType()->isVoidType();
6800b57cec5SDimitry Andric     HasNoReturn = FD->isNoReturn();
6810b57cec5SDimitry Andric   }
6820b57cec5SDimitry Andric   else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
6830b57cec5SDimitry Andric     ReturnsVoid = MD->getReturnType()->isVoidType();
6840b57cec5SDimitry Andric     HasNoReturn = MD->hasAttr<NoReturnAttr>();
6850b57cec5SDimitry Andric   }
6860b57cec5SDimitry Andric   else if (isa<BlockDecl>(D)) {
6870b57cec5SDimitry Andric     if (const FunctionType *FT =
6880b57cec5SDimitry Andric           BlockType->getPointeeType()->getAs<FunctionType>()) {
6890b57cec5SDimitry Andric       if (FT->getReturnType()->isVoidType())
6900b57cec5SDimitry Andric         ReturnsVoid = true;
6910b57cec5SDimitry Andric       if (FT->getNoReturnAttr())
6920b57cec5SDimitry Andric         HasNoReturn = true;
6930b57cec5SDimitry Andric     }
6940b57cec5SDimitry Andric   }
6950b57cec5SDimitry Andric 
6960b57cec5SDimitry Andric   DiagnosticsEngine &Diags = S.getDiagnostics();
6970b57cec5SDimitry Andric 
6980b57cec5SDimitry Andric   // Short circuit for compilation speed.
6990b57cec5SDimitry Andric   if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
7000b57cec5SDimitry Andric       return;
7010b57cec5SDimitry Andric   SourceLocation LBrace = Body->getBeginLoc(), RBrace = Body->getEndLoc();
7020b57cec5SDimitry Andric   auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) {
7030b57cec5SDimitry Andric     if (IsCoroutine)
7040b57cec5SDimitry Andric       S.Diag(Loc, DiagID) << FSI->CoroutinePromise->getType();
7050b57cec5SDimitry Andric     else
7060b57cec5SDimitry Andric       S.Diag(Loc, DiagID);
7070b57cec5SDimitry Andric   };
7080b57cec5SDimitry Andric 
7090b57cec5SDimitry Andric   // cpu_dispatch functions permit empty function bodies for ICC compatibility.
7100b57cec5SDimitry Andric   if (D->getAsFunction() && D->getAsFunction()->isCPUDispatchMultiVersion())
7110b57cec5SDimitry Andric     return;
7120b57cec5SDimitry Andric 
7130b57cec5SDimitry Andric   // Either in a function body compound statement, or a function-try-block.
7140b57cec5SDimitry Andric   switch (CheckFallThrough(AC)) {
7150b57cec5SDimitry Andric     case UnknownFallThrough:
7160b57cec5SDimitry Andric       break;
7170b57cec5SDimitry Andric 
7180b57cec5SDimitry Andric     case MaybeFallThrough:
7190b57cec5SDimitry Andric       if (HasNoReturn)
7200b57cec5SDimitry Andric         EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);
7210b57cec5SDimitry Andric       else if (!ReturnsVoid)
7220b57cec5SDimitry Andric         EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);
7230b57cec5SDimitry Andric       break;
7240b57cec5SDimitry Andric     case AlwaysFallThrough:
7250b57cec5SDimitry Andric       if (HasNoReturn)
7260b57cec5SDimitry Andric         EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);
7270b57cec5SDimitry Andric       else if (!ReturnsVoid)
7280b57cec5SDimitry Andric         EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
7290b57cec5SDimitry Andric       break;
7300b57cec5SDimitry Andric     case NeverFallThroughOrReturn:
7310b57cec5SDimitry Andric       if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
7320b57cec5SDimitry Andric         if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
7330b57cec5SDimitry Andric           S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
7340b57cec5SDimitry Andric         } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
7350b57cec5SDimitry Andric           S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
7360b57cec5SDimitry Andric         } else {
7370b57cec5SDimitry Andric           S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
7380b57cec5SDimitry Andric         }
7390b57cec5SDimitry Andric       }
7400b57cec5SDimitry Andric       break;
7410b57cec5SDimitry Andric     case NeverFallThrough:
7420b57cec5SDimitry Andric       break;
7430b57cec5SDimitry Andric   }
7440b57cec5SDimitry Andric }
7450b57cec5SDimitry Andric 
7460b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
7470b57cec5SDimitry Andric // -Wuninitialized
7480b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
7490b57cec5SDimitry Andric 
7500b57cec5SDimitry Andric namespace {
7510b57cec5SDimitry Andric /// ContainsReference - A visitor class to search for references to
7520b57cec5SDimitry Andric /// a particular declaration (the needle) within any evaluated component of an
7530b57cec5SDimitry Andric /// expression (recursively).
7540b57cec5SDimitry Andric class ContainsReference : public ConstEvaluatedExprVisitor<ContainsReference> {
7550b57cec5SDimitry Andric   bool FoundReference;
7560b57cec5SDimitry Andric   const DeclRefExpr *Needle;
7570b57cec5SDimitry Andric 
7580b57cec5SDimitry Andric public:
7590b57cec5SDimitry Andric   typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited;
7600b57cec5SDimitry Andric 
ContainsReference(ASTContext & Context,const DeclRefExpr * Needle)7610b57cec5SDimitry Andric   ContainsReference(ASTContext &Context, const DeclRefExpr *Needle)
7620b57cec5SDimitry Andric     : Inherited(Context), FoundReference(false), Needle(Needle) {}
7630b57cec5SDimitry Andric 
VisitExpr(const Expr * E)7640b57cec5SDimitry Andric   void VisitExpr(const Expr *E) {
7650b57cec5SDimitry Andric     // Stop evaluating if we already have a reference.
7660b57cec5SDimitry Andric     if (FoundReference)
7670b57cec5SDimitry Andric       return;
7680b57cec5SDimitry Andric 
7690b57cec5SDimitry Andric     Inherited::VisitExpr(E);
7700b57cec5SDimitry Andric   }
7710b57cec5SDimitry Andric 
VisitDeclRefExpr(const DeclRefExpr * E)7720b57cec5SDimitry Andric   void VisitDeclRefExpr(const DeclRefExpr *E) {
7730b57cec5SDimitry Andric     if (E == Needle)
7740b57cec5SDimitry Andric       FoundReference = true;
7750b57cec5SDimitry Andric     else
7760b57cec5SDimitry Andric       Inherited::VisitDeclRefExpr(E);
7770b57cec5SDimitry Andric   }
7780b57cec5SDimitry Andric 
doesContainReference() const7790b57cec5SDimitry Andric   bool doesContainReference() const { return FoundReference; }
7800b57cec5SDimitry Andric };
7810b57cec5SDimitry Andric } // anonymous namespace
7820b57cec5SDimitry Andric 
SuggestInitializationFixit(Sema & S,const VarDecl * VD)7830b57cec5SDimitry Andric static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
7840b57cec5SDimitry Andric   QualType VariableTy = VD->getType().getCanonicalType();
7850b57cec5SDimitry Andric   if (VariableTy->isBlockPointerType() &&
7860b57cec5SDimitry Andric       !VD->hasAttr<BlocksAttr>()) {
7870b57cec5SDimitry Andric     S.Diag(VD->getLocation(), diag::note_block_var_fixit_add_initialization)
7880b57cec5SDimitry Andric         << VD->getDeclName()
7890b57cec5SDimitry Andric         << FixItHint::CreateInsertion(VD->getLocation(), "__block ");
7900b57cec5SDimitry Andric     return true;
7910b57cec5SDimitry Andric   }
7920b57cec5SDimitry Andric 
7930b57cec5SDimitry Andric   // Don't issue a fixit if there is already an initializer.
7940b57cec5SDimitry Andric   if (VD->getInit())
7950b57cec5SDimitry Andric     return false;
7960b57cec5SDimitry Andric 
7970b57cec5SDimitry Andric   // Don't suggest a fixit inside macros.
7980b57cec5SDimitry Andric   if (VD->getEndLoc().isMacroID())
7990b57cec5SDimitry Andric     return false;
8000b57cec5SDimitry Andric 
8010b57cec5SDimitry Andric   SourceLocation Loc = S.getLocForEndOfToken(VD->getEndLoc());
8020b57cec5SDimitry Andric 
8030b57cec5SDimitry Andric   // Suggest possible initialization (if any).
8040b57cec5SDimitry Andric   std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc);
8050b57cec5SDimitry Andric   if (Init.empty())
8060b57cec5SDimitry Andric     return false;
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric   S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName()
8090b57cec5SDimitry Andric     << FixItHint::CreateInsertion(Loc, Init);
8100b57cec5SDimitry Andric   return true;
8110b57cec5SDimitry Andric }
8120b57cec5SDimitry Andric 
8130b57cec5SDimitry Andric /// Create a fixit to remove an if-like statement, on the assumption that its
8140b57cec5SDimitry Andric /// condition is CondVal.
CreateIfFixit(Sema & S,const Stmt * If,const Stmt * Then,const Stmt * Else,bool CondVal,FixItHint & Fixit1,FixItHint & Fixit2)8150b57cec5SDimitry Andric static void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then,
8160b57cec5SDimitry Andric                           const Stmt *Else, bool CondVal,
8170b57cec5SDimitry Andric                           FixItHint &Fixit1, FixItHint &Fixit2) {
8180b57cec5SDimitry Andric   if (CondVal) {
8190b57cec5SDimitry Andric     // If condition is always true, remove all but the 'then'.
8200b57cec5SDimitry Andric     Fixit1 = FixItHint::CreateRemoval(
8210b57cec5SDimitry Andric         CharSourceRange::getCharRange(If->getBeginLoc(), Then->getBeginLoc()));
8220b57cec5SDimitry Andric     if (Else) {
8230b57cec5SDimitry Andric       SourceLocation ElseKwLoc = S.getLocForEndOfToken(Then->getEndLoc());
8240b57cec5SDimitry Andric       Fixit2 =
8250b57cec5SDimitry Andric           FixItHint::CreateRemoval(SourceRange(ElseKwLoc, Else->getEndLoc()));
8260b57cec5SDimitry Andric     }
8270b57cec5SDimitry Andric   } else {
8280b57cec5SDimitry Andric     // If condition is always false, remove all but the 'else'.
8290b57cec5SDimitry Andric     if (Else)
8300b57cec5SDimitry Andric       Fixit1 = FixItHint::CreateRemoval(CharSourceRange::getCharRange(
8310b57cec5SDimitry Andric           If->getBeginLoc(), Else->getBeginLoc()));
8320b57cec5SDimitry Andric     else
8330b57cec5SDimitry Andric       Fixit1 = FixItHint::CreateRemoval(If->getSourceRange());
8340b57cec5SDimitry Andric   }
8350b57cec5SDimitry Andric }
8360b57cec5SDimitry Andric 
8370b57cec5SDimitry Andric /// DiagUninitUse -- Helper function to produce a diagnostic for an
8380b57cec5SDimitry Andric /// uninitialized use of a variable.
DiagUninitUse(Sema & S,const VarDecl * VD,const UninitUse & Use,bool IsCapturedByBlock)8390b57cec5SDimitry Andric static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
8400b57cec5SDimitry Andric                           bool IsCapturedByBlock) {
8410b57cec5SDimitry Andric   bool Diagnosed = false;
8420b57cec5SDimitry Andric 
8430b57cec5SDimitry Andric   switch (Use.getKind()) {
8440b57cec5SDimitry Andric   case UninitUse::Always:
8450b57cec5SDimitry Andric     S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_var)
8460b57cec5SDimitry Andric         << VD->getDeclName() << IsCapturedByBlock
8470b57cec5SDimitry Andric         << Use.getUser()->getSourceRange();
8480b57cec5SDimitry Andric     return;
8490b57cec5SDimitry Andric 
8500b57cec5SDimitry Andric   case UninitUse::AfterDecl:
8510b57cec5SDimitry Andric   case UninitUse::AfterCall:
8520b57cec5SDimitry Andric     S.Diag(VD->getLocation(), diag::warn_sometimes_uninit_var)
8530b57cec5SDimitry Andric       << VD->getDeclName() << IsCapturedByBlock
8540b57cec5SDimitry Andric       << (Use.getKind() == UninitUse::AfterDecl ? 4 : 5)
8550b57cec5SDimitry Andric       << const_cast<DeclContext*>(VD->getLexicalDeclContext())
8560b57cec5SDimitry Andric       << VD->getSourceRange();
8570b57cec5SDimitry Andric     S.Diag(Use.getUser()->getBeginLoc(), diag::note_uninit_var_use)
8580b57cec5SDimitry Andric         << IsCapturedByBlock << Use.getUser()->getSourceRange();
8590b57cec5SDimitry Andric     return;
8600b57cec5SDimitry Andric 
8610b57cec5SDimitry Andric   case UninitUse::Maybe:
8620b57cec5SDimitry Andric   case UninitUse::Sometimes:
8630b57cec5SDimitry Andric     // Carry on to report sometimes-uninitialized branches, if possible,
8640b57cec5SDimitry Andric     // or a 'may be used uninitialized' diagnostic otherwise.
8650b57cec5SDimitry Andric     break;
8660b57cec5SDimitry Andric   }
8670b57cec5SDimitry Andric 
8680b57cec5SDimitry Andric   // Diagnose each branch which leads to a sometimes-uninitialized use.
8690b57cec5SDimitry Andric   for (UninitUse::branch_iterator I = Use.branch_begin(), E = Use.branch_end();
8700b57cec5SDimitry Andric        I != E; ++I) {
8710b57cec5SDimitry Andric     assert(Use.getKind() == UninitUse::Sometimes);
8720b57cec5SDimitry Andric 
8730b57cec5SDimitry Andric     const Expr *User = Use.getUser();
8740b57cec5SDimitry Andric     const Stmt *Term = I->Terminator;
8750b57cec5SDimitry Andric 
8760b57cec5SDimitry Andric     // Information used when building the diagnostic.
8770b57cec5SDimitry Andric     unsigned DiagKind;
8780b57cec5SDimitry Andric     StringRef Str;
8790b57cec5SDimitry Andric     SourceRange Range;
8800b57cec5SDimitry Andric 
8810b57cec5SDimitry Andric     // FixIts to suppress the diagnostic by removing the dead condition.
8820b57cec5SDimitry Andric     // For all binary terminators, branch 0 is taken if the condition is true,
8830b57cec5SDimitry Andric     // and branch 1 is taken if the condition is false.
8840b57cec5SDimitry Andric     int RemoveDiagKind = -1;
8850b57cec5SDimitry Andric     const char *FixitStr =
8860b57cec5SDimitry Andric         S.getLangOpts().CPlusPlus ? (I->Output ? "true" : "false")
8870b57cec5SDimitry Andric                                   : (I->Output ? "1" : "0");
8880b57cec5SDimitry Andric     FixItHint Fixit1, Fixit2;
8890b57cec5SDimitry Andric 
8900b57cec5SDimitry Andric     switch (Term ? Term->getStmtClass() : Stmt::DeclStmtClass) {
8910b57cec5SDimitry Andric     default:
8920b57cec5SDimitry Andric       // Don't know how to report this. Just fall back to 'may be used
8930b57cec5SDimitry Andric       // uninitialized'. FIXME: Can this happen?
8940b57cec5SDimitry Andric       continue;
8950b57cec5SDimitry Andric 
8960b57cec5SDimitry Andric     // "condition is true / condition is false".
8970b57cec5SDimitry Andric     case Stmt::IfStmtClass: {
8980b57cec5SDimitry Andric       const IfStmt *IS = cast<IfStmt>(Term);
8990b57cec5SDimitry Andric       DiagKind = 0;
9000b57cec5SDimitry Andric       Str = "if";
9010b57cec5SDimitry Andric       Range = IS->getCond()->getSourceRange();
9020b57cec5SDimitry Andric       RemoveDiagKind = 0;
9030b57cec5SDimitry Andric       CreateIfFixit(S, IS, IS->getThen(), IS->getElse(),
9040b57cec5SDimitry Andric                     I->Output, Fixit1, Fixit2);
9050b57cec5SDimitry Andric       break;
9060b57cec5SDimitry Andric     }
9070b57cec5SDimitry Andric     case Stmt::ConditionalOperatorClass: {
9080b57cec5SDimitry Andric       const ConditionalOperator *CO = cast<ConditionalOperator>(Term);
9090b57cec5SDimitry Andric       DiagKind = 0;
9100b57cec5SDimitry Andric       Str = "?:";
9110b57cec5SDimitry Andric       Range = CO->getCond()->getSourceRange();
9120b57cec5SDimitry Andric       RemoveDiagKind = 0;
9130b57cec5SDimitry Andric       CreateIfFixit(S, CO, CO->getTrueExpr(), CO->getFalseExpr(),
9140b57cec5SDimitry Andric                     I->Output, Fixit1, Fixit2);
9150b57cec5SDimitry Andric       break;
9160b57cec5SDimitry Andric     }
9170b57cec5SDimitry Andric     case Stmt::BinaryOperatorClass: {
9180b57cec5SDimitry Andric       const BinaryOperator *BO = cast<BinaryOperator>(Term);
9190b57cec5SDimitry Andric       if (!BO->isLogicalOp())
9200b57cec5SDimitry Andric         continue;
9210b57cec5SDimitry Andric       DiagKind = 0;
9220b57cec5SDimitry Andric       Str = BO->getOpcodeStr();
9230b57cec5SDimitry Andric       Range = BO->getLHS()->getSourceRange();
9240b57cec5SDimitry Andric       RemoveDiagKind = 0;
9250b57cec5SDimitry Andric       if ((BO->getOpcode() == BO_LAnd && I->Output) ||
9260b57cec5SDimitry Andric           (BO->getOpcode() == BO_LOr && !I->Output))
9270b57cec5SDimitry Andric         // true && y -> y, false || y -> y.
9280b57cec5SDimitry Andric         Fixit1 = FixItHint::CreateRemoval(
9290b57cec5SDimitry Andric             SourceRange(BO->getBeginLoc(), BO->getOperatorLoc()));
9300b57cec5SDimitry Andric       else
9310b57cec5SDimitry Andric         // false && y -> false, true || y -> true.
9320b57cec5SDimitry Andric         Fixit1 = FixItHint::CreateReplacement(BO->getSourceRange(), FixitStr);
9330b57cec5SDimitry Andric       break;
9340b57cec5SDimitry Andric     }
9350b57cec5SDimitry Andric 
9360b57cec5SDimitry Andric     // "loop is entered / loop is exited".
9370b57cec5SDimitry Andric     case Stmt::WhileStmtClass:
9380b57cec5SDimitry Andric       DiagKind = 1;
9390b57cec5SDimitry Andric       Str = "while";
9400b57cec5SDimitry Andric       Range = cast<WhileStmt>(Term)->getCond()->getSourceRange();
9410b57cec5SDimitry Andric       RemoveDiagKind = 1;
9420b57cec5SDimitry Andric       Fixit1 = FixItHint::CreateReplacement(Range, FixitStr);
9430b57cec5SDimitry Andric       break;
9440b57cec5SDimitry Andric     case Stmt::ForStmtClass:
9450b57cec5SDimitry Andric       DiagKind = 1;
9460b57cec5SDimitry Andric       Str = "for";
9470b57cec5SDimitry Andric       Range = cast<ForStmt>(Term)->getCond()->getSourceRange();
9480b57cec5SDimitry Andric       RemoveDiagKind = 1;
9490b57cec5SDimitry Andric       if (I->Output)
9500b57cec5SDimitry Andric         Fixit1 = FixItHint::CreateRemoval(Range);
9510b57cec5SDimitry Andric       else
9520b57cec5SDimitry Andric         Fixit1 = FixItHint::CreateReplacement(Range, FixitStr);
9530b57cec5SDimitry Andric       break;
9540b57cec5SDimitry Andric     case Stmt::CXXForRangeStmtClass:
9550b57cec5SDimitry Andric       if (I->Output == 1) {
9560b57cec5SDimitry Andric         // The use occurs if a range-based for loop's body never executes.
9570b57cec5SDimitry Andric         // That may be impossible, and there's no syntactic fix for this,
9580b57cec5SDimitry Andric         // so treat it as a 'may be uninitialized' case.
9590b57cec5SDimitry Andric         continue;
9600b57cec5SDimitry Andric       }
9610b57cec5SDimitry Andric       DiagKind = 1;
9620b57cec5SDimitry Andric       Str = "for";
9630b57cec5SDimitry Andric       Range = cast<CXXForRangeStmt>(Term)->getRangeInit()->getSourceRange();
9640b57cec5SDimitry Andric       break;
9650b57cec5SDimitry Andric 
9660b57cec5SDimitry Andric     // "condition is true / loop is exited".
9670b57cec5SDimitry Andric     case Stmt::DoStmtClass:
9680b57cec5SDimitry Andric       DiagKind = 2;
9690b57cec5SDimitry Andric       Str = "do";
9700b57cec5SDimitry Andric       Range = cast<DoStmt>(Term)->getCond()->getSourceRange();
9710b57cec5SDimitry Andric       RemoveDiagKind = 1;
9720b57cec5SDimitry Andric       Fixit1 = FixItHint::CreateReplacement(Range, FixitStr);
9730b57cec5SDimitry Andric       break;
9740b57cec5SDimitry Andric 
9750b57cec5SDimitry Andric     // "switch case is taken".
9760b57cec5SDimitry Andric     case Stmt::CaseStmtClass:
9770b57cec5SDimitry Andric       DiagKind = 3;
9780b57cec5SDimitry Andric       Str = "case";
9790b57cec5SDimitry Andric       Range = cast<CaseStmt>(Term)->getLHS()->getSourceRange();
9800b57cec5SDimitry Andric       break;
9810b57cec5SDimitry Andric     case Stmt::DefaultStmtClass:
9820b57cec5SDimitry Andric       DiagKind = 3;
9830b57cec5SDimitry Andric       Str = "default";
9840b57cec5SDimitry Andric       Range = cast<DefaultStmt>(Term)->getDefaultLoc();
9850b57cec5SDimitry Andric       break;
9860b57cec5SDimitry Andric     }
9870b57cec5SDimitry Andric 
9880b57cec5SDimitry Andric     S.Diag(Range.getBegin(), diag::warn_sometimes_uninit_var)
9890b57cec5SDimitry Andric       << VD->getDeclName() << IsCapturedByBlock << DiagKind
9900b57cec5SDimitry Andric       << Str << I->Output << Range;
9910b57cec5SDimitry Andric     S.Diag(User->getBeginLoc(), diag::note_uninit_var_use)
9920b57cec5SDimitry Andric         << IsCapturedByBlock << User->getSourceRange();
9930b57cec5SDimitry Andric     if (RemoveDiagKind != -1)
9940b57cec5SDimitry Andric       S.Diag(Fixit1.RemoveRange.getBegin(), diag::note_uninit_fixit_remove_cond)
9950b57cec5SDimitry Andric         << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
9960b57cec5SDimitry Andric 
9970b57cec5SDimitry Andric     Diagnosed = true;
9980b57cec5SDimitry Andric   }
9990b57cec5SDimitry Andric 
10000b57cec5SDimitry Andric   if (!Diagnosed)
10010b57cec5SDimitry Andric     S.Diag(Use.getUser()->getBeginLoc(), diag::warn_maybe_uninit_var)
10020b57cec5SDimitry Andric         << VD->getDeclName() << IsCapturedByBlock
10030b57cec5SDimitry Andric         << Use.getUser()->getSourceRange();
10040b57cec5SDimitry Andric }
10050b57cec5SDimitry Andric 
10065ffd83dbSDimitry Andric /// Diagnose uninitialized const reference usages.
DiagnoseUninitializedConstRefUse(Sema & S,const VarDecl * VD,const UninitUse & Use)10075ffd83dbSDimitry Andric static bool DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD,
10085ffd83dbSDimitry Andric                                              const UninitUse &Use) {
10095ffd83dbSDimitry Andric   S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_const_reference)
10105ffd83dbSDimitry Andric       << VD->getDeclName() << Use.getUser()->getSourceRange();
10115ffd83dbSDimitry Andric   return true;
10125ffd83dbSDimitry Andric }
10135ffd83dbSDimitry Andric 
10140b57cec5SDimitry Andric /// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an
10150b57cec5SDimitry Andric /// uninitialized variable. This manages the different forms of diagnostic
10160b57cec5SDimitry Andric /// emitted for particular types of uses. Returns true if the use was diagnosed
10170b57cec5SDimitry Andric /// as a warning. If a particular use is one we omit warnings for, returns
10180b57cec5SDimitry Andric /// false.
DiagnoseUninitializedUse(Sema & S,const VarDecl * VD,const UninitUse & Use,bool alwaysReportSelfInit=false)10190b57cec5SDimitry Andric static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
10200b57cec5SDimitry Andric                                      const UninitUse &Use,
10210b57cec5SDimitry Andric                                      bool alwaysReportSelfInit = false) {
10220b57cec5SDimitry Andric   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Use.getUser())) {
10230b57cec5SDimitry Andric     // Inspect the initializer of the variable declaration which is
10240b57cec5SDimitry Andric     // being referenced prior to its initialization. We emit
10250b57cec5SDimitry Andric     // specialized diagnostics for self-initialization, and we
10260b57cec5SDimitry Andric     // specifically avoid warning about self references which take the
10270b57cec5SDimitry Andric     // form of:
10280b57cec5SDimitry Andric     //
10290b57cec5SDimitry Andric     //   int x = x;
10300b57cec5SDimitry Andric     //
10310b57cec5SDimitry Andric     // This is used to indicate to GCC that 'x' is intentionally left
10320b57cec5SDimitry Andric     // uninitialized. Proven code paths which access 'x' in
10330b57cec5SDimitry Andric     // an uninitialized state after this will still warn.
10340b57cec5SDimitry Andric     if (const Expr *Initializer = VD->getInit()) {
10350b57cec5SDimitry Andric       if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts())
10360b57cec5SDimitry Andric         return false;
10370b57cec5SDimitry Andric 
10380b57cec5SDimitry Andric       ContainsReference CR(S.Context, DRE);
10390b57cec5SDimitry Andric       CR.Visit(Initializer);
10400b57cec5SDimitry Andric       if (CR.doesContainReference()) {
10410b57cec5SDimitry Andric         S.Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
10420b57cec5SDimitry Andric             << VD->getDeclName() << VD->getLocation() << DRE->getSourceRange();
10430b57cec5SDimitry Andric         return true;
10440b57cec5SDimitry Andric       }
10450b57cec5SDimitry Andric     }
10460b57cec5SDimitry Andric 
10470b57cec5SDimitry Andric     DiagUninitUse(S, VD, Use, false);
10480b57cec5SDimitry Andric   } else {
10490b57cec5SDimitry Andric     const BlockExpr *BE = cast<BlockExpr>(Use.getUser());
10500b57cec5SDimitry Andric     if (VD->getType()->isBlockPointerType() && !VD->hasAttr<BlocksAttr>())
10510b57cec5SDimitry Andric       S.Diag(BE->getBeginLoc(),
10520b57cec5SDimitry Andric              diag::warn_uninit_byref_blockvar_captured_by_block)
10530b57cec5SDimitry Andric           << VD->getDeclName()
10540b57cec5SDimitry Andric           << VD->getType().getQualifiers().hasObjCLifetime();
10550b57cec5SDimitry Andric     else
10560b57cec5SDimitry Andric       DiagUninitUse(S, VD, Use, true);
10570b57cec5SDimitry Andric   }
10580b57cec5SDimitry Andric 
10590b57cec5SDimitry Andric   // Report where the variable was declared when the use wasn't within
10600b57cec5SDimitry Andric   // the initializer of that declaration & we didn't already suggest
10610b57cec5SDimitry Andric   // an initialization fixit.
10620b57cec5SDimitry Andric   if (!SuggestInitializationFixit(S, VD))
10630b57cec5SDimitry Andric     S.Diag(VD->getBeginLoc(), diag::note_var_declared_here)
10640b57cec5SDimitry Andric         << VD->getDeclName();
10650b57cec5SDimitry Andric 
10660b57cec5SDimitry Andric   return true;
10670b57cec5SDimitry Andric }
10680b57cec5SDimitry Andric 
10690b57cec5SDimitry Andric namespace {
10700b57cec5SDimitry Andric   class FallthroughMapper : public RecursiveASTVisitor<FallthroughMapper> {
10710b57cec5SDimitry Andric   public:
FallthroughMapper(Sema & S)10720b57cec5SDimitry Andric     FallthroughMapper(Sema &S)
10730b57cec5SDimitry Andric       : FoundSwitchStatements(false),
10740b57cec5SDimitry Andric         S(S) {
10750b57cec5SDimitry Andric     }
10760b57cec5SDimitry Andric 
foundSwitchStatements() const10770b57cec5SDimitry Andric     bool foundSwitchStatements() const { return FoundSwitchStatements; }
10780b57cec5SDimitry Andric 
markFallthroughVisited(const AttributedStmt * Stmt)10790b57cec5SDimitry Andric     void markFallthroughVisited(const AttributedStmt *Stmt) {
10800b57cec5SDimitry Andric       bool Found = FallthroughStmts.erase(Stmt);
10810b57cec5SDimitry Andric       assert(Found);
10820b57cec5SDimitry Andric       (void)Found;
10830b57cec5SDimitry Andric     }
10840b57cec5SDimitry Andric 
10850b57cec5SDimitry Andric     typedef llvm::SmallPtrSet<const AttributedStmt*, 8> AttrStmts;
10860b57cec5SDimitry Andric 
getFallthroughStmts() const10870b57cec5SDimitry Andric     const AttrStmts &getFallthroughStmts() const {
10880b57cec5SDimitry Andric       return FallthroughStmts;
10890b57cec5SDimitry Andric     }
10900b57cec5SDimitry Andric 
fillReachableBlocks(CFG * Cfg)10910b57cec5SDimitry Andric     void fillReachableBlocks(CFG *Cfg) {
10920b57cec5SDimitry Andric       assert(ReachableBlocks.empty() && "ReachableBlocks already filled");
10930b57cec5SDimitry Andric       std::deque<const CFGBlock *> BlockQueue;
10940b57cec5SDimitry Andric 
10950b57cec5SDimitry Andric       ReachableBlocks.insert(&Cfg->getEntry());
10960b57cec5SDimitry Andric       BlockQueue.push_back(&Cfg->getEntry());
10970b57cec5SDimitry Andric       // Mark all case blocks reachable to avoid problems with switching on
10980b57cec5SDimitry Andric       // constants, covered enums, etc.
10990b57cec5SDimitry Andric       // These blocks can contain fall-through annotations, and we don't want to
11000b57cec5SDimitry Andric       // issue a warn_fallthrough_attr_unreachable for them.
11010b57cec5SDimitry Andric       for (const auto *B : *Cfg) {
11020b57cec5SDimitry Andric         const Stmt *L = B->getLabel();
1103*0fca6ea1SDimitry Andric         if (isa_and_nonnull<SwitchCase>(L) && ReachableBlocks.insert(B).second)
11040b57cec5SDimitry Andric           BlockQueue.push_back(B);
11050b57cec5SDimitry Andric       }
11060b57cec5SDimitry Andric 
11070b57cec5SDimitry Andric       while (!BlockQueue.empty()) {
11080b57cec5SDimitry Andric         const CFGBlock *P = BlockQueue.front();
11090b57cec5SDimitry Andric         BlockQueue.pop_front();
1110349cc55cSDimitry Andric         for (const CFGBlock *B : P->succs()) {
1111349cc55cSDimitry Andric           if (B && ReachableBlocks.insert(B).second)
1112349cc55cSDimitry Andric             BlockQueue.push_back(B);
11130b57cec5SDimitry Andric         }
11140b57cec5SDimitry Andric       }
11150b57cec5SDimitry Andric     }
11160b57cec5SDimitry Andric 
checkFallThroughIntoBlock(const CFGBlock & B,int & AnnotatedCnt,bool IsTemplateInstantiation)11170b57cec5SDimitry Andric     bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt,
11180b57cec5SDimitry Andric                                    bool IsTemplateInstantiation) {
11190b57cec5SDimitry Andric       assert(!ReachableBlocks.empty() && "ReachableBlocks empty");
11200b57cec5SDimitry Andric 
11210b57cec5SDimitry Andric       int UnannotatedCnt = 0;
11220b57cec5SDimitry Andric       AnnotatedCnt = 0;
11230b57cec5SDimitry Andric 
11240b57cec5SDimitry Andric       std::deque<const CFGBlock*> BlockQueue(B.pred_begin(), B.pred_end());
11250b57cec5SDimitry Andric       while (!BlockQueue.empty()) {
11260b57cec5SDimitry Andric         const CFGBlock *P = BlockQueue.front();
11270b57cec5SDimitry Andric         BlockQueue.pop_front();
11280b57cec5SDimitry Andric         if (!P) continue;
11290b57cec5SDimitry Andric 
11300b57cec5SDimitry Andric         const Stmt *Term = P->getTerminatorStmt();
1131*0fca6ea1SDimitry Andric         if (isa_and_nonnull<SwitchStmt>(Term))
11320b57cec5SDimitry Andric           continue; // Switch statement, good.
11330b57cec5SDimitry Andric 
11340b57cec5SDimitry Andric         const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->getLabel());
11350b57cec5SDimitry Andric         if (SW && SW->getSubStmt() == B.getLabel() && P->begin() == P->end())
11360b57cec5SDimitry Andric           continue; // Previous case label has no statements, good.
11370b57cec5SDimitry Andric 
11380b57cec5SDimitry Andric         const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->getLabel());
11390b57cec5SDimitry Andric         if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end())
11400b57cec5SDimitry Andric           continue; // Case label is preceded with a normal label, good.
11410b57cec5SDimitry Andric 
11420b57cec5SDimitry Andric         if (!ReachableBlocks.count(P)) {
1143349cc55cSDimitry Andric           for (const CFGElement &Elem : llvm::reverse(*P)) {
1144bdd1243dSDimitry Andric             if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) {
11450b57cec5SDimitry Andric             if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
11460b57cec5SDimitry Andric               // Don't issue a warning for an unreachable fallthrough
11470b57cec5SDimitry Andric               // attribute in template instantiations as it may not be
11480b57cec5SDimitry Andric               // unreachable in all instantiations of the template.
11490b57cec5SDimitry Andric               if (!IsTemplateInstantiation)
11500b57cec5SDimitry Andric                 S.Diag(AS->getBeginLoc(),
1151349cc55cSDimitry Andric                        diag::warn_unreachable_fallthrough_attr);
11520b57cec5SDimitry Andric               markFallthroughVisited(AS);
11530b57cec5SDimitry Andric               ++AnnotatedCnt;
11540b57cec5SDimitry Andric               break;
11550b57cec5SDimitry Andric             }
11560b57cec5SDimitry Andric             // Don't care about other unreachable statements.
11570b57cec5SDimitry Andric             }
11580b57cec5SDimitry Andric           }
11590b57cec5SDimitry Andric           // If there are no unreachable statements, this may be a special
11600b57cec5SDimitry Andric           // case in CFG:
11610b57cec5SDimitry Andric           // case X: {
11620b57cec5SDimitry Andric           //    A a;  // A has a destructor.
11630b57cec5SDimitry Andric           //    break;
11640b57cec5SDimitry Andric           // }
11650b57cec5SDimitry Andric           // // <<<< This place is represented by a 'hanging' CFG block.
11660b57cec5SDimitry Andric           // case Y:
11670b57cec5SDimitry Andric           continue;
11680b57cec5SDimitry Andric         }
11690b57cec5SDimitry Andric 
11700b57cec5SDimitry Andric         const Stmt *LastStmt = getLastStmt(*P);
11710b57cec5SDimitry Andric         if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {
11720b57cec5SDimitry Andric           markFallthroughVisited(AS);
11730b57cec5SDimitry Andric           ++AnnotatedCnt;
11740b57cec5SDimitry Andric           continue; // Fallthrough annotation, good.
11750b57cec5SDimitry Andric         }
11760b57cec5SDimitry Andric 
11770b57cec5SDimitry Andric         if (!LastStmt) { // This block contains no executable statements.
11780b57cec5SDimitry Andric           // Traverse its predecessors.
11790b57cec5SDimitry Andric           std::copy(P->pred_begin(), P->pred_end(),
11800b57cec5SDimitry Andric                     std::back_inserter(BlockQueue));
11810b57cec5SDimitry Andric           continue;
11820b57cec5SDimitry Andric         }
11830b57cec5SDimitry Andric 
11840b57cec5SDimitry Andric         ++UnannotatedCnt;
11850b57cec5SDimitry Andric       }
11860b57cec5SDimitry Andric       return !!UnannotatedCnt;
11870b57cec5SDimitry Andric     }
11880b57cec5SDimitry Andric 
11890b57cec5SDimitry Andric     // RecursiveASTVisitor setup.
shouldWalkTypesOfTypeLocs() const11900b57cec5SDimitry Andric     bool shouldWalkTypesOfTypeLocs() const { return false; }
11910b57cec5SDimitry Andric 
VisitAttributedStmt(AttributedStmt * S)11920b57cec5SDimitry Andric     bool VisitAttributedStmt(AttributedStmt *S) {
11930b57cec5SDimitry Andric       if (asFallThroughAttr(S))
11940b57cec5SDimitry Andric         FallthroughStmts.insert(S);
11950b57cec5SDimitry Andric       return true;
11960b57cec5SDimitry Andric     }
11970b57cec5SDimitry Andric 
VisitSwitchStmt(SwitchStmt * S)11980b57cec5SDimitry Andric     bool VisitSwitchStmt(SwitchStmt *S) {
11990b57cec5SDimitry Andric       FoundSwitchStatements = true;
12000b57cec5SDimitry Andric       return true;
12010b57cec5SDimitry Andric     }
12020b57cec5SDimitry Andric 
12030b57cec5SDimitry Andric     // We don't want to traverse local type declarations. We analyze their
12040b57cec5SDimitry Andric     // methods separately.
TraverseDecl(Decl * D)12050b57cec5SDimitry Andric     bool TraverseDecl(Decl *D) { return true; }
12060b57cec5SDimitry Andric 
12070b57cec5SDimitry Andric     // We analyze lambda bodies separately. Skip them here.
TraverseLambdaExpr(LambdaExpr * LE)12080b57cec5SDimitry Andric     bool TraverseLambdaExpr(LambdaExpr *LE) {
12090b57cec5SDimitry Andric       // Traverse the captures, but not the body.
1210480093f4SDimitry Andric       for (const auto C : zip(LE->captures(), LE->capture_inits()))
12110b57cec5SDimitry Andric         TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C));
12120b57cec5SDimitry Andric       return true;
12130b57cec5SDimitry Andric     }
12140b57cec5SDimitry Andric 
12150b57cec5SDimitry Andric   private:
12160b57cec5SDimitry Andric 
asFallThroughAttr(const Stmt * S)12170b57cec5SDimitry Andric     static const AttributedStmt *asFallThroughAttr(const Stmt *S) {
12180b57cec5SDimitry Andric       if (const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
12190b57cec5SDimitry Andric         if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs()))
12200b57cec5SDimitry Andric           return AS;
12210b57cec5SDimitry Andric       }
12220b57cec5SDimitry Andric       return nullptr;
12230b57cec5SDimitry Andric     }
12240b57cec5SDimitry Andric 
getLastStmt(const CFGBlock & B)12250b57cec5SDimitry Andric     static const Stmt *getLastStmt(const CFGBlock &B) {
12260b57cec5SDimitry Andric       if (const Stmt *Term = B.getTerminatorStmt())
12270b57cec5SDimitry Andric         return Term;
1228349cc55cSDimitry Andric       for (const CFGElement &Elem : llvm::reverse(B))
1229bdd1243dSDimitry Andric         if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
12300b57cec5SDimitry Andric           return CS->getStmt();
12310b57cec5SDimitry Andric       // Workaround to detect a statement thrown out by CFGBuilder:
12320b57cec5SDimitry Andric       //   case X: {} case Y:
12330b57cec5SDimitry Andric       //   case X: ; case Y:
12340b57cec5SDimitry Andric       if (const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.getLabel()))
12350b57cec5SDimitry Andric         if (!isa<SwitchCase>(SW->getSubStmt()))
12360b57cec5SDimitry Andric           return SW->getSubStmt();
12370b57cec5SDimitry Andric 
12380b57cec5SDimitry Andric       return nullptr;
12390b57cec5SDimitry Andric     }
12400b57cec5SDimitry Andric 
12410b57cec5SDimitry Andric     bool FoundSwitchStatements;
12420b57cec5SDimitry Andric     AttrStmts FallthroughStmts;
12430b57cec5SDimitry Andric     Sema &S;
12440b57cec5SDimitry Andric     llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
12450b57cec5SDimitry Andric   };
12460b57cec5SDimitry Andric } // anonymous namespace
12470b57cec5SDimitry Andric 
getFallthroughAttrSpelling(Preprocessor & PP,SourceLocation Loc)12480b57cec5SDimitry Andric static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
12490b57cec5SDimitry Andric                                             SourceLocation Loc) {
12500b57cec5SDimitry Andric   TokenValue FallthroughTokens[] = {
12510b57cec5SDimitry Andric     tok::l_square, tok::l_square,
12520b57cec5SDimitry Andric     PP.getIdentifierInfo("fallthrough"),
12530b57cec5SDimitry Andric     tok::r_square, tok::r_square
12540b57cec5SDimitry Andric   };
12550b57cec5SDimitry Andric 
12560b57cec5SDimitry Andric   TokenValue ClangFallthroughTokens[] = {
12570b57cec5SDimitry Andric     tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"),
12580b57cec5SDimitry Andric     tok::coloncolon, PP.getIdentifierInfo("fallthrough"),
12590b57cec5SDimitry Andric     tok::r_square, tok::r_square
12600b57cec5SDimitry Andric   };
12610b57cec5SDimitry Andric 
12625f757f3fSDimitry Andric   bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17 && !PP.getLangOpts().C23;
12630b57cec5SDimitry Andric 
12640b57cec5SDimitry Andric   StringRef MacroName;
12650b57cec5SDimitry Andric   if (PreferClangAttr)
12660b57cec5SDimitry Andric     MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens);
12670b57cec5SDimitry Andric   if (MacroName.empty())
12680b57cec5SDimitry Andric     MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens);
12690b57cec5SDimitry Andric   if (MacroName.empty() && !PreferClangAttr)
12700b57cec5SDimitry Andric     MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens);
1271a7dea167SDimitry Andric   if (MacroName.empty()) {
1272a7dea167SDimitry Andric     if (!PreferClangAttr)
1273a7dea167SDimitry Andric       MacroName = "[[fallthrough]]";
1274a7dea167SDimitry Andric     else if (PP.getLangOpts().CPlusPlus)
1275a7dea167SDimitry Andric       MacroName = "[[clang::fallthrough]]";
1276a7dea167SDimitry Andric     else
1277a7dea167SDimitry Andric       MacroName = "__attribute__((fallthrough))";
1278a7dea167SDimitry Andric   }
12790b57cec5SDimitry Andric   return MacroName;
12800b57cec5SDimitry Andric }
12810b57cec5SDimitry Andric 
DiagnoseSwitchLabelsFallthrough(Sema & S,AnalysisDeclContext & AC,bool PerFunction)12820b57cec5SDimitry Andric static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
12830b57cec5SDimitry Andric                                             bool PerFunction) {
12840b57cec5SDimitry Andric   FallthroughMapper FM(S);
12850b57cec5SDimitry Andric   FM.TraverseStmt(AC.getBody());
12860b57cec5SDimitry Andric 
12870b57cec5SDimitry Andric   if (!FM.foundSwitchStatements())
12880b57cec5SDimitry Andric     return;
12890b57cec5SDimitry Andric 
12900b57cec5SDimitry Andric   if (PerFunction && FM.getFallthroughStmts().empty())
12910b57cec5SDimitry Andric     return;
12920b57cec5SDimitry Andric 
12930b57cec5SDimitry Andric   CFG *Cfg = AC.getCFG();
12940b57cec5SDimitry Andric 
12950b57cec5SDimitry Andric   if (!Cfg)
12960b57cec5SDimitry Andric     return;
12970b57cec5SDimitry Andric 
12980b57cec5SDimitry Andric   FM.fillReachableBlocks(Cfg);
12990b57cec5SDimitry Andric 
13000b57cec5SDimitry Andric   for (const CFGBlock *B : llvm::reverse(*Cfg)) {
13010b57cec5SDimitry Andric     const Stmt *Label = B->getLabel();
13020b57cec5SDimitry Andric 
130381ad6265SDimitry Andric     if (!isa_and_nonnull<SwitchCase>(Label))
13040b57cec5SDimitry Andric       continue;
13050b57cec5SDimitry Andric 
13060b57cec5SDimitry Andric     int AnnotatedCnt;
13070b57cec5SDimitry Andric 
13080b57cec5SDimitry Andric     bool IsTemplateInstantiation = false;
13090b57cec5SDimitry Andric     if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(AC.getDecl()))
13100b57cec5SDimitry Andric       IsTemplateInstantiation = Function->isTemplateInstantiation();
13110b57cec5SDimitry Andric     if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,
13120b57cec5SDimitry Andric                                       IsTemplateInstantiation))
13130b57cec5SDimitry Andric       continue;
13140b57cec5SDimitry Andric 
13150b57cec5SDimitry Andric     S.Diag(Label->getBeginLoc(),
13160b57cec5SDimitry Andric            PerFunction ? diag::warn_unannotated_fallthrough_per_function
13170b57cec5SDimitry Andric                        : diag::warn_unannotated_fallthrough);
13180b57cec5SDimitry Andric 
13190b57cec5SDimitry Andric     if (!AnnotatedCnt) {
13200b57cec5SDimitry Andric       SourceLocation L = Label->getBeginLoc();
13210b57cec5SDimitry Andric       if (L.isMacroID())
13220b57cec5SDimitry Andric         continue;
1323a7dea167SDimitry Andric 
13240b57cec5SDimitry Andric       const Stmt *Term = B->getTerminatorStmt();
13250b57cec5SDimitry Andric       // Skip empty cases.
13260b57cec5SDimitry Andric       while (B->empty() && !Term && B->succ_size() == 1) {
13270b57cec5SDimitry Andric         B = *B->succ_begin();
13280b57cec5SDimitry Andric         Term = B->getTerminatorStmt();
13290b57cec5SDimitry Andric       }
1330*0fca6ea1SDimitry Andric       if (!(B->empty() && isa_and_nonnull<BreakStmt>(Term))) {
13310b57cec5SDimitry Andric         Preprocessor &PP = S.getPreprocessor();
13320b57cec5SDimitry Andric         StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L);
13330b57cec5SDimitry Andric         SmallString<64> TextToInsert(AnnotationSpelling);
13340b57cec5SDimitry Andric         TextToInsert += "; ";
1335a7dea167SDimitry Andric         S.Diag(L, diag::note_insert_fallthrough_fixit)
1336a7dea167SDimitry Andric             << AnnotationSpelling
1337a7dea167SDimitry Andric             << FixItHint::CreateInsertion(L, TextToInsert);
13380b57cec5SDimitry Andric       }
1339a7dea167SDimitry Andric       S.Diag(L, diag::note_insert_break_fixit)
1340a7dea167SDimitry Andric           << FixItHint::CreateInsertion(L, "break; ");
13410b57cec5SDimitry Andric     }
13420b57cec5SDimitry Andric   }
13430b57cec5SDimitry Andric 
13440b57cec5SDimitry Andric   for (const auto *F : FM.getFallthroughStmts())
13450b57cec5SDimitry Andric     S.Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement);
13460b57cec5SDimitry Andric }
13470b57cec5SDimitry Andric 
isInLoop(const ASTContext & Ctx,const ParentMap & PM,const Stmt * S)13480b57cec5SDimitry Andric static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM,
13490b57cec5SDimitry Andric                      const Stmt *S) {
13500b57cec5SDimitry Andric   assert(S);
13510b57cec5SDimitry Andric 
13520b57cec5SDimitry Andric   do {
13530b57cec5SDimitry Andric     switch (S->getStmtClass()) {
13540b57cec5SDimitry Andric     case Stmt::ForStmtClass:
13550b57cec5SDimitry Andric     case Stmt::WhileStmtClass:
13560b57cec5SDimitry Andric     case Stmt::CXXForRangeStmtClass:
13570b57cec5SDimitry Andric     case Stmt::ObjCForCollectionStmtClass:
13580b57cec5SDimitry Andric       return true;
13590b57cec5SDimitry Andric     case Stmt::DoStmtClass: {
13600b57cec5SDimitry Andric       Expr::EvalResult Result;
13610b57cec5SDimitry Andric       if (!cast<DoStmt>(S)->getCond()->EvaluateAsInt(Result, Ctx))
13620b57cec5SDimitry Andric         return true;
13630b57cec5SDimitry Andric       return Result.Val.getInt().getBoolValue();
13640b57cec5SDimitry Andric     }
13650b57cec5SDimitry Andric     default:
13660b57cec5SDimitry Andric       break;
13670b57cec5SDimitry Andric     }
13680b57cec5SDimitry Andric   } while ((S = PM.getParent(S)));
13690b57cec5SDimitry Andric 
13700b57cec5SDimitry Andric   return false;
13710b57cec5SDimitry Andric }
13720b57cec5SDimitry Andric 
diagnoseRepeatedUseOfWeak(Sema & S,const sema::FunctionScopeInfo * CurFn,const Decl * D,const ParentMap & PM)13730b57cec5SDimitry Andric static void diagnoseRepeatedUseOfWeak(Sema &S,
13740b57cec5SDimitry Andric                                       const sema::FunctionScopeInfo *CurFn,
13750b57cec5SDimitry Andric                                       const Decl *D,
13760b57cec5SDimitry Andric                                       const ParentMap &PM) {
13770b57cec5SDimitry Andric   typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy;
13780b57cec5SDimitry Andric   typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap;
13790b57cec5SDimitry Andric   typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector;
13800b57cec5SDimitry Andric   typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
13810b57cec5SDimitry Andric   StmtUsesPair;
13820b57cec5SDimitry Andric 
13830b57cec5SDimitry Andric   ASTContext &Ctx = S.getASTContext();
13840b57cec5SDimitry Andric 
13850b57cec5SDimitry Andric   const WeakObjectUseMap &WeakMap = CurFn->getWeakObjectUses();
13860b57cec5SDimitry Andric 
13870b57cec5SDimitry Andric   // Extract all weak objects that are referenced more than once.
13880b57cec5SDimitry Andric   SmallVector<StmtUsesPair, 8> UsesByStmt;
13890b57cec5SDimitry Andric   for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end();
13900b57cec5SDimitry Andric        I != E; ++I) {
13910b57cec5SDimitry Andric     const WeakUseVector &Uses = I->second;
13920b57cec5SDimitry Andric 
13930b57cec5SDimitry Andric     // Find the first read of the weak object.
13940b57cec5SDimitry Andric     WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
13950b57cec5SDimitry Andric     for ( ; UI != UE; ++UI) {
13960b57cec5SDimitry Andric       if (UI->isUnsafe())
13970b57cec5SDimitry Andric         break;
13980b57cec5SDimitry Andric     }
13990b57cec5SDimitry Andric 
14000b57cec5SDimitry Andric     // If there were only writes to this object, don't warn.
14010b57cec5SDimitry Andric     if (UI == UE)
14020b57cec5SDimitry Andric       continue;
14030b57cec5SDimitry Andric 
14040b57cec5SDimitry Andric     // If there was only one read, followed by any number of writes, and the
14050b57cec5SDimitry Andric     // read is not within a loop, don't warn. Additionally, don't warn in a
14060b57cec5SDimitry Andric     // loop if the base object is a local variable -- local variables are often
14070b57cec5SDimitry Andric     // changed in loops.
14080b57cec5SDimitry Andric     if (UI == Uses.begin()) {
14090b57cec5SDimitry Andric       WeakUseVector::const_iterator UI2 = UI;
14100b57cec5SDimitry Andric       for (++UI2; UI2 != UE; ++UI2)
14110b57cec5SDimitry Andric         if (UI2->isUnsafe())
14120b57cec5SDimitry Andric           break;
14130b57cec5SDimitry Andric 
14140b57cec5SDimitry Andric       if (UI2 == UE) {
14150b57cec5SDimitry Andric         if (!isInLoop(Ctx, PM, UI->getUseExpr()))
14160b57cec5SDimitry Andric           continue;
14170b57cec5SDimitry Andric 
14180b57cec5SDimitry Andric         const WeakObjectProfileTy &Profile = I->first;
14190b57cec5SDimitry Andric         if (!Profile.isExactProfile())
14200b57cec5SDimitry Andric           continue;
14210b57cec5SDimitry Andric 
14220b57cec5SDimitry Andric         const NamedDecl *Base = Profile.getBase();
14230b57cec5SDimitry Andric         if (!Base)
14240b57cec5SDimitry Andric           Base = Profile.getProperty();
14250b57cec5SDimitry Andric         assert(Base && "A profile always has a base or property.");
14260b57cec5SDimitry Andric 
14270b57cec5SDimitry Andric         if (const VarDecl *BaseVar = dyn_cast<VarDecl>(Base))
14280b57cec5SDimitry Andric           if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(Base))
14290b57cec5SDimitry Andric             continue;
14300b57cec5SDimitry Andric       }
14310b57cec5SDimitry Andric     }
14320b57cec5SDimitry Andric 
14330b57cec5SDimitry Andric     UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
14340b57cec5SDimitry Andric   }
14350b57cec5SDimitry Andric 
14360b57cec5SDimitry Andric   if (UsesByStmt.empty())
14370b57cec5SDimitry Andric     return;
14380b57cec5SDimitry Andric 
14390b57cec5SDimitry Andric   // Sort by first use so that we emit the warnings in a deterministic order.
14400b57cec5SDimitry Andric   SourceManager &SM = S.getSourceManager();
14410b57cec5SDimitry Andric   llvm::sort(UsesByStmt,
14420b57cec5SDimitry Andric              [&SM](const StmtUsesPair &LHS, const StmtUsesPair &RHS) {
14430b57cec5SDimitry Andric                return SM.isBeforeInTranslationUnit(LHS.first->getBeginLoc(),
14440b57cec5SDimitry Andric                                                    RHS.first->getBeginLoc());
14450b57cec5SDimitry Andric              });
14460b57cec5SDimitry Andric 
14470b57cec5SDimitry Andric   // Classify the current code body for better warning text.
14480b57cec5SDimitry Andric   // This enum should stay in sync with the cases in
14490b57cec5SDimitry Andric   // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.
14500b57cec5SDimitry Andric   // FIXME: Should we use a common classification enum and the same set of
14510b57cec5SDimitry Andric   // possibilities all throughout Sema?
14520b57cec5SDimitry Andric   enum {
14530b57cec5SDimitry Andric     Function,
14540b57cec5SDimitry Andric     Method,
14550b57cec5SDimitry Andric     Block,
14560b57cec5SDimitry Andric     Lambda
14570b57cec5SDimitry Andric   } FunctionKind;
14580b57cec5SDimitry Andric 
14590b57cec5SDimitry Andric   if (isa<sema::BlockScopeInfo>(CurFn))
14600b57cec5SDimitry Andric     FunctionKind = Block;
14610b57cec5SDimitry Andric   else if (isa<sema::LambdaScopeInfo>(CurFn))
14620b57cec5SDimitry Andric     FunctionKind = Lambda;
14630b57cec5SDimitry Andric   else if (isa<ObjCMethodDecl>(D))
14640b57cec5SDimitry Andric     FunctionKind = Method;
14650b57cec5SDimitry Andric   else
14660b57cec5SDimitry Andric     FunctionKind = Function;
14670b57cec5SDimitry Andric 
14680b57cec5SDimitry Andric   // Iterate through the sorted problems and emit warnings for each.
14690b57cec5SDimitry Andric   for (const auto &P : UsesByStmt) {
14700b57cec5SDimitry Andric     const Stmt *FirstRead = P.first;
14710b57cec5SDimitry Andric     const WeakObjectProfileTy &Key = P.second->first;
14720b57cec5SDimitry Andric     const WeakUseVector &Uses = P.second->second;
14730b57cec5SDimitry Andric 
14740b57cec5SDimitry Andric     // For complicated expressions like 'a.b.c' and 'x.b.c', WeakObjectProfileTy
14750b57cec5SDimitry Andric     // may not contain enough information to determine that these are different
14760b57cec5SDimitry Andric     // properties. We can only be 100% sure of a repeated use in certain cases,
14770b57cec5SDimitry Andric     // and we adjust the diagnostic kind accordingly so that the less certain
14780b57cec5SDimitry Andric     // case can be turned off if it is too noisy.
14790b57cec5SDimitry Andric     unsigned DiagKind;
14800b57cec5SDimitry Andric     if (Key.isExactProfile())
14810b57cec5SDimitry Andric       DiagKind = diag::warn_arc_repeated_use_of_weak;
14820b57cec5SDimitry Andric     else
14830b57cec5SDimitry Andric       DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
14840b57cec5SDimitry Andric 
14850b57cec5SDimitry Andric     // Classify the weak object being accessed for better warning text.
14860b57cec5SDimitry Andric     // This enum should stay in sync with the cases in
14870b57cec5SDimitry Andric     // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.
14880b57cec5SDimitry Andric     enum {
14890b57cec5SDimitry Andric       Variable,
14900b57cec5SDimitry Andric       Property,
14910b57cec5SDimitry Andric       ImplicitProperty,
14920b57cec5SDimitry Andric       Ivar
14930b57cec5SDimitry Andric     } ObjectKind;
14940b57cec5SDimitry Andric 
14950b57cec5SDimitry Andric     const NamedDecl *KeyProp = Key.getProperty();
14960b57cec5SDimitry Andric     if (isa<VarDecl>(KeyProp))
14970b57cec5SDimitry Andric       ObjectKind = Variable;
14980b57cec5SDimitry Andric     else if (isa<ObjCPropertyDecl>(KeyProp))
14990b57cec5SDimitry Andric       ObjectKind = Property;
15000b57cec5SDimitry Andric     else if (isa<ObjCMethodDecl>(KeyProp))
15010b57cec5SDimitry Andric       ObjectKind = ImplicitProperty;
15020b57cec5SDimitry Andric     else if (isa<ObjCIvarDecl>(KeyProp))
15030b57cec5SDimitry Andric       ObjectKind = Ivar;
15040b57cec5SDimitry Andric     else
15050b57cec5SDimitry Andric       llvm_unreachable("Unexpected weak object kind!");
15060b57cec5SDimitry Andric 
15070b57cec5SDimitry Andric     // Do not warn about IBOutlet weak property receivers being set to null
15080b57cec5SDimitry Andric     // since they are typically only used from the main thread.
15090b57cec5SDimitry Andric     if (const ObjCPropertyDecl *Prop = dyn_cast<ObjCPropertyDecl>(KeyProp))
15100b57cec5SDimitry Andric       if (Prop->hasAttr<IBOutletAttr>())
15110b57cec5SDimitry Andric         continue;
15120b57cec5SDimitry Andric 
15130b57cec5SDimitry Andric     // Show the first time the object was read.
15140b57cec5SDimitry Andric     S.Diag(FirstRead->getBeginLoc(), DiagKind)
15150b57cec5SDimitry Andric         << int(ObjectKind) << KeyProp << int(FunctionKind)
15160b57cec5SDimitry Andric         << FirstRead->getSourceRange();
15170b57cec5SDimitry Andric 
15180b57cec5SDimitry Andric     // Print all the other accesses as notes.
15190b57cec5SDimitry Andric     for (const auto &Use : Uses) {
15200b57cec5SDimitry Andric       if (Use.getUseExpr() == FirstRead)
15210b57cec5SDimitry Andric         continue;
15220b57cec5SDimitry Andric       S.Diag(Use.getUseExpr()->getBeginLoc(),
15230b57cec5SDimitry Andric              diag::note_arc_weak_also_accessed_here)
15240b57cec5SDimitry Andric           << Use.getUseExpr()->getSourceRange();
15250b57cec5SDimitry Andric     }
15260b57cec5SDimitry Andric   }
15270b57cec5SDimitry Andric }
15280b57cec5SDimitry Andric 
1529fe6060f1SDimitry Andric namespace clang {
1530fe6060f1SDimitry Andric namespace {
1531fe6060f1SDimitry Andric typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
1532fe6060f1SDimitry Andric typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;
1533fe6060f1SDimitry Andric typedef std::list<DelayedDiag> DiagList;
1534fe6060f1SDimitry Andric 
1535fe6060f1SDimitry Andric struct SortDiagBySourceLocation {
1536fe6060f1SDimitry Andric   SourceManager &SM;
SortDiagBySourceLocationclang::__anon9476153b0c11::SortDiagBySourceLocation1537fe6060f1SDimitry Andric   SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {}
1538fe6060f1SDimitry Andric 
operator ()clang::__anon9476153b0c11::SortDiagBySourceLocation1539fe6060f1SDimitry Andric   bool operator()(const DelayedDiag &left, const DelayedDiag &right) {
1540fe6060f1SDimitry Andric     // Although this call will be slow, this is only called when outputting
1541fe6060f1SDimitry Andric     // multiple warnings.
1542fe6060f1SDimitry Andric     return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
1543fe6060f1SDimitry Andric   }
1544fe6060f1SDimitry Andric };
1545fe6060f1SDimitry Andric } // anonymous namespace
1546fe6060f1SDimitry Andric } // namespace clang
1547fe6060f1SDimitry Andric 
15480b57cec5SDimitry Andric namespace {
15490b57cec5SDimitry Andric class UninitValsDiagReporter : public UninitVariablesHandler {
15500b57cec5SDimitry Andric   Sema &S;
15510b57cec5SDimitry Andric   typedef SmallVector<UninitUse, 2> UsesVec;
15520b57cec5SDimitry Andric   typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
15530b57cec5SDimitry Andric   // Prefer using MapVector to DenseMap, so that iteration order will be
15540b57cec5SDimitry Andric   // the same as insertion order. This is needed to obtain a deterministic
15550b57cec5SDimitry Andric   // order of diagnostics when calling flushDiagnostics().
15560b57cec5SDimitry Andric   typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
15570b57cec5SDimitry Andric   UsesMap uses;
15585ffd83dbSDimitry Andric   UsesMap constRefUses;
15590b57cec5SDimitry Andric 
15600b57cec5SDimitry Andric public:
UninitValsDiagReporter(Sema & S)15610b57cec5SDimitry Andric   UninitValsDiagReporter(Sema &S) : S(S) {}
~UninitValsDiagReporter()15620b57cec5SDimitry Andric   ~UninitValsDiagReporter() override { flushDiagnostics(); }
15630b57cec5SDimitry Andric 
getUses(UsesMap & um,const VarDecl * vd)15645ffd83dbSDimitry Andric   MappedType &getUses(UsesMap &um, const VarDecl *vd) {
15655ffd83dbSDimitry Andric     MappedType &V = um[vd];
15660b57cec5SDimitry Andric     if (!V.getPointer())
15670b57cec5SDimitry Andric       V.setPointer(new UsesVec());
15680b57cec5SDimitry Andric     return V;
15690b57cec5SDimitry Andric   }
15700b57cec5SDimitry Andric 
handleUseOfUninitVariable(const VarDecl * vd,const UninitUse & use)15710b57cec5SDimitry Andric   void handleUseOfUninitVariable(const VarDecl *vd,
15720b57cec5SDimitry Andric                                  const UninitUse &use) override {
15735ffd83dbSDimitry Andric     getUses(uses, vd).getPointer()->push_back(use);
15745ffd83dbSDimitry Andric   }
15755ffd83dbSDimitry Andric 
handleConstRefUseOfUninitVariable(const VarDecl * vd,const UninitUse & use)15765ffd83dbSDimitry Andric   void handleConstRefUseOfUninitVariable(const VarDecl *vd,
15775ffd83dbSDimitry Andric                                          const UninitUse &use) override {
15785ffd83dbSDimitry Andric     getUses(constRefUses, vd).getPointer()->push_back(use);
15790b57cec5SDimitry Andric   }
15800b57cec5SDimitry Andric 
handleSelfInit(const VarDecl * vd)15810b57cec5SDimitry Andric   void handleSelfInit(const VarDecl *vd) override {
15825ffd83dbSDimitry Andric     getUses(uses, vd).setInt(true);
15835ffd83dbSDimitry Andric     getUses(constRefUses, vd).setInt(true);
15840b57cec5SDimitry Andric   }
15850b57cec5SDimitry Andric 
flushDiagnostics()15860b57cec5SDimitry Andric   void flushDiagnostics() {
15870b57cec5SDimitry Andric     for (const auto &P : uses) {
15880b57cec5SDimitry Andric       const VarDecl *vd = P.first;
15890b57cec5SDimitry Andric       const MappedType &V = P.second;
15900b57cec5SDimitry Andric 
15910b57cec5SDimitry Andric       UsesVec *vec = V.getPointer();
15920b57cec5SDimitry Andric       bool hasSelfInit = V.getInt();
15930b57cec5SDimitry Andric 
15940b57cec5SDimitry Andric       // Specially handle the case where we have uses of an uninitialized
15950b57cec5SDimitry Andric       // variable, but the root cause is an idiomatic self-init.  We want
15960b57cec5SDimitry Andric       // to report the diagnostic at the self-init since that is the root cause.
15970b57cec5SDimitry Andric       if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
15980b57cec5SDimitry Andric         DiagnoseUninitializedUse(S, vd,
15990b57cec5SDimitry Andric                                  UninitUse(vd->getInit()->IgnoreParenCasts(),
16000b57cec5SDimitry Andric                                            /* isAlwaysUninit */ true),
16010b57cec5SDimitry Andric                                  /* alwaysReportSelfInit */ true);
16020b57cec5SDimitry Andric       else {
16030b57cec5SDimitry Andric         // Sort the uses by their SourceLocations.  While not strictly
16040b57cec5SDimitry Andric         // guaranteed to produce them in line/column order, this will provide
16050b57cec5SDimitry Andric         // a stable ordering.
1606fcaf7f86SDimitry Andric         llvm::sort(*vec, [](const UninitUse &a, const UninitUse &b) {
16070b57cec5SDimitry Andric           // Prefer a more confident report over a less confident one.
16080b57cec5SDimitry Andric           if (a.getKind() != b.getKind())
16090b57cec5SDimitry Andric             return a.getKind() > b.getKind();
16100b57cec5SDimitry Andric           return a.getUser()->getBeginLoc() < b.getUser()->getBeginLoc();
16110b57cec5SDimitry Andric         });
16120b57cec5SDimitry Andric 
16130b57cec5SDimitry Andric         for (const auto &U : *vec) {
16140b57cec5SDimitry Andric           // If we have self-init, downgrade all uses to 'may be uninitialized'.
16150b57cec5SDimitry Andric           UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U;
16160b57cec5SDimitry Andric 
16170b57cec5SDimitry Andric           if (DiagnoseUninitializedUse(S, vd, Use))
16180b57cec5SDimitry Andric             // Skip further diagnostics for this variable. We try to warn only
16190b57cec5SDimitry Andric             // on the first point at which a variable is used uninitialized.
16200b57cec5SDimitry Andric             break;
16210b57cec5SDimitry Andric         }
16220b57cec5SDimitry Andric       }
16230b57cec5SDimitry Andric 
16240b57cec5SDimitry Andric       // Release the uses vector.
16250b57cec5SDimitry Andric       delete vec;
16260b57cec5SDimitry Andric     }
16270b57cec5SDimitry Andric 
16280b57cec5SDimitry Andric     uses.clear();
16295ffd83dbSDimitry Andric 
16305ffd83dbSDimitry Andric     // Flush all const reference uses diags.
16315ffd83dbSDimitry Andric     for (const auto &P : constRefUses) {
16325ffd83dbSDimitry Andric       const VarDecl *vd = P.first;
16335ffd83dbSDimitry Andric       const MappedType &V = P.second;
16345ffd83dbSDimitry Andric 
16355ffd83dbSDimitry Andric       UsesVec *vec = V.getPointer();
16365ffd83dbSDimitry Andric       bool hasSelfInit = V.getInt();
16375ffd83dbSDimitry Andric 
16385ffd83dbSDimitry Andric       if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
16395ffd83dbSDimitry Andric         DiagnoseUninitializedUse(S, vd,
16405ffd83dbSDimitry Andric                                  UninitUse(vd->getInit()->IgnoreParenCasts(),
16415ffd83dbSDimitry Andric                                            /* isAlwaysUninit */ true),
16425ffd83dbSDimitry Andric                                  /* alwaysReportSelfInit */ true);
16435ffd83dbSDimitry Andric       else {
16445ffd83dbSDimitry Andric         for (const auto &U : *vec) {
16455ffd83dbSDimitry Andric           if (DiagnoseUninitializedConstRefUse(S, vd, U))
16465ffd83dbSDimitry Andric             break;
16475ffd83dbSDimitry Andric         }
16485ffd83dbSDimitry Andric       }
16495ffd83dbSDimitry Andric 
16505ffd83dbSDimitry Andric       // Release the uses vector.
16515ffd83dbSDimitry Andric       delete vec;
16525ffd83dbSDimitry Andric     }
16535ffd83dbSDimitry Andric 
16545ffd83dbSDimitry Andric     constRefUses.clear();
16550b57cec5SDimitry Andric   }
16560b57cec5SDimitry Andric 
16570b57cec5SDimitry Andric private:
hasAlwaysUninitializedUse(const UsesVec * vec)16580b57cec5SDimitry Andric   static bool hasAlwaysUninitializedUse(const UsesVec* vec) {
1659349cc55cSDimitry Andric     return llvm::any_of(*vec, [](const UninitUse &U) {
16600b57cec5SDimitry Andric       return U.getKind() == UninitUse::Always ||
16610b57cec5SDimitry Andric              U.getKind() == UninitUse::AfterCall ||
16620b57cec5SDimitry Andric              U.getKind() == UninitUse::AfterDecl;
16630b57cec5SDimitry Andric     });
16640b57cec5SDimitry Andric   }
16650b57cec5SDimitry Andric };
1666e8d8bef9SDimitry Andric 
1667fe6060f1SDimitry Andric /// Inter-procedural data for the called-once checker.
1668fe6060f1SDimitry Andric class CalledOnceInterProceduralData {
1669fe6060f1SDimitry Andric public:
1670fe6060f1SDimitry Andric   // Add the delayed warning for the given block.
addDelayedWarning(const BlockDecl * Block,PartialDiagnosticAt && Warning)1671fe6060f1SDimitry Andric   void addDelayedWarning(const BlockDecl *Block,
1672fe6060f1SDimitry Andric                          PartialDiagnosticAt &&Warning) {
1673fe6060f1SDimitry Andric     DelayedBlockWarnings[Block].emplace_back(std::move(Warning));
1674fe6060f1SDimitry Andric   }
1675fe6060f1SDimitry Andric   // Report all of the warnings we've gathered for the given block.
flushWarnings(const BlockDecl * Block,Sema & S)1676fe6060f1SDimitry Andric   void flushWarnings(const BlockDecl *Block, Sema &S) {
1677fe6060f1SDimitry Andric     for (const PartialDiagnosticAt &Delayed : DelayedBlockWarnings[Block])
1678fe6060f1SDimitry Andric       S.Diag(Delayed.first, Delayed.second);
1679fe6060f1SDimitry Andric 
1680fe6060f1SDimitry Andric     discardWarnings(Block);
1681fe6060f1SDimitry Andric   }
1682fe6060f1SDimitry Andric   // Discard all of the warnings we've gathered for the given block.
discardWarnings(const BlockDecl * Block)1683fe6060f1SDimitry Andric   void discardWarnings(const BlockDecl *Block) {
1684fe6060f1SDimitry Andric     DelayedBlockWarnings.erase(Block);
1685fe6060f1SDimitry Andric   }
1686fe6060f1SDimitry Andric 
1687fe6060f1SDimitry Andric private:
1688fe6060f1SDimitry Andric   using DelayedDiagnostics = SmallVector<PartialDiagnosticAt, 2>;
1689fe6060f1SDimitry Andric   llvm::DenseMap<const BlockDecl *, DelayedDiagnostics> DelayedBlockWarnings;
1690fe6060f1SDimitry Andric };
1691fe6060f1SDimitry Andric 
1692e8d8bef9SDimitry Andric class CalledOnceCheckReporter : public CalledOnceCheckHandler {
1693e8d8bef9SDimitry Andric public:
CalledOnceCheckReporter(Sema & S,CalledOnceInterProceduralData & Data)1694fe6060f1SDimitry Andric   CalledOnceCheckReporter(Sema &S, CalledOnceInterProceduralData &Data)
1695fe6060f1SDimitry Andric       : S(S), Data(Data) {}
handleDoubleCall(const ParmVarDecl * Parameter,const Expr * Call,const Expr * PrevCall,bool IsCompletionHandler,bool Poised)1696e8d8bef9SDimitry Andric   void handleDoubleCall(const ParmVarDecl *Parameter, const Expr *Call,
1697e8d8bef9SDimitry Andric                         const Expr *PrevCall, bool IsCompletionHandler,
1698e8d8bef9SDimitry Andric                         bool Poised) override {
1699e8d8bef9SDimitry Andric     auto DiagToReport = IsCompletionHandler
1700e8d8bef9SDimitry Andric                             ? diag::warn_completion_handler_called_twice
1701e8d8bef9SDimitry Andric                             : diag::warn_called_once_gets_called_twice;
1702e8d8bef9SDimitry Andric     S.Diag(Call->getBeginLoc(), DiagToReport) << Parameter;
1703e8d8bef9SDimitry Andric     S.Diag(PrevCall->getBeginLoc(), diag::note_called_once_gets_called_twice)
1704e8d8bef9SDimitry Andric         << Poised;
1705e8d8bef9SDimitry Andric   }
1706e8d8bef9SDimitry Andric 
handleNeverCalled(const ParmVarDecl * Parameter,bool IsCompletionHandler)1707e8d8bef9SDimitry Andric   void handleNeverCalled(const ParmVarDecl *Parameter,
1708e8d8bef9SDimitry Andric                          bool IsCompletionHandler) override {
1709e8d8bef9SDimitry Andric     auto DiagToReport = IsCompletionHandler
1710e8d8bef9SDimitry Andric                             ? diag::warn_completion_handler_never_called
1711e8d8bef9SDimitry Andric                             : diag::warn_called_once_never_called;
1712e8d8bef9SDimitry Andric     S.Diag(Parameter->getBeginLoc(), DiagToReport)
1713e8d8bef9SDimitry Andric         << Parameter << /* Captured */ false;
1714e8d8bef9SDimitry Andric   }
1715e8d8bef9SDimitry Andric 
handleNeverCalled(const ParmVarDecl * Parameter,const Decl * Function,const Stmt * Where,NeverCalledReason Reason,bool IsCalledDirectly,bool IsCompletionHandler)1716fe6060f1SDimitry Andric   void handleNeverCalled(const ParmVarDecl *Parameter, const Decl *Function,
1717fe6060f1SDimitry Andric                          const Stmt *Where, NeverCalledReason Reason,
1718fe6060f1SDimitry Andric                          bool IsCalledDirectly,
1719e8d8bef9SDimitry Andric                          bool IsCompletionHandler) override {
1720e8d8bef9SDimitry Andric     auto DiagToReport = IsCompletionHandler
1721e8d8bef9SDimitry Andric                             ? diag::warn_completion_handler_never_called_when
1722e8d8bef9SDimitry Andric                             : diag::warn_called_once_never_called_when;
1723fe6060f1SDimitry Andric     PartialDiagnosticAt Warning(Where->getBeginLoc(), S.PDiag(DiagToReport)
1724fe6060f1SDimitry Andric                                                           << Parameter
1725fe6060f1SDimitry Andric                                                           << IsCalledDirectly
1726fe6060f1SDimitry Andric                                                           << (unsigned)Reason);
1727fe6060f1SDimitry Andric 
1728fe6060f1SDimitry Andric     if (const auto *Block = dyn_cast<BlockDecl>(Function)) {
1729fe6060f1SDimitry Andric       // We shouldn't report these warnings on blocks immediately
1730fe6060f1SDimitry Andric       Data.addDelayedWarning(Block, std::move(Warning));
1731fe6060f1SDimitry Andric     } else {
1732fe6060f1SDimitry Andric       S.Diag(Warning.first, Warning.second);
1733fe6060f1SDimitry Andric     }
1734e8d8bef9SDimitry Andric   }
1735e8d8bef9SDimitry Andric 
handleCapturedNeverCalled(const ParmVarDecl * Parameter,const Decl * Where,bool IsCompletionHandler)1736e8d8bef9SDimitry Andric   void handleCapturedNeverCalled(const ParmVarDecl *Parameter,
1737e8d8bef9SDimitry Andric                                  const Decl *Where,
1738e8d8bef9SDimitry Andric                                  bool IsCompletionHandler) override {
1739e8d8bef9SDimitry Andric     auto DiagToReport = IsCompletionHandler
1740e8d8bef9SDimitry Andric                             ? diag::warn_completion_handler_never_called
1741e8d8bef9SDimitry Andric                             : diag::warn_called_once_never_called;
1742e8d8bef9SDimitry Andric     S.Diag(Where->getBeginLoc(), DiagToReport)
1743e8d8bef9SDimitry Andric         << Parameter << /* Captured */ true;
1744e8d8bef9SDimitry Andric   }
1745e8d8bef9SDimitry Andric 
1746fe6060f1SDimitry Andric   void
handleBlockThatIsGuaranteedToBeCalledOnce(const BlockDecl * Block)1747fe6060f1SDimitry Andric   handleBlockThatIsGuaranteedToBeCalledOnce(const BlockDecl *Block) override {
1748fe6060f1SDimitry Andric     Data.flushWarnings(Block, S);
1749fe6060f1SDimitry Andric   }
1750fe6060f1SDimitry Andric 
handleBlockWithNoGuarantees(const BlockDecl * Block)1751fe6060f1SDimitry Andric   void handleBlockWithNoGuarantees(const BlockDecl *Block) override {
1752fe6060f1SDimitry Andric     Data.discardWarnings(Block);
1753fe6060f1SDimitry Andric   }
1754fe6060f1SDimitry Andric 
1755e8d8bef9SDimitry Andric private:
1756e8d8bef9SDimitry Andric   Sema &S;
1757fe6060f1SDimitry Andric   CalledOnceInterProceduralData &Data;
1758e8d8bef9SDimitry Andric };
1759e8d8bef9SDimitry Andric 
1760e8d8bef9SDimitry Andric constexpr unsigned CalledOnceWarnings[] = {
1761e8d8bef9SDimitry Andric     diag::warn_called_once_never_called,
1762e8d8bef9SDimitry Andric     diag::warn_called_once_never_called_when,
1763e8d8bef9SDimitry Andric     diag::warn_called_once_gets_called_twice};
1764e8d8bef9SDimitry Andric 
1765e8d8bef9SDimitry Andric constexpr unsigned CompletionHandlerWarnings[]{
1766e8d8bef9SDimitry Andric     diag::warn_completion_handler_never_called,
1767e8d8bef9SDimitry Andric     diag::warn_completion_handler_never_called_when,
1768e8d8bef9SDimitry Andric     diag::warn_completion_handler_called_twice};
1769e8d8bef9SDimitry Andric 
shouldAnalyzeCalledOnceImpl(llvm::ArrayRef<unsigned> DiagIDs,const DiagnosticsEngine & Diags,SourceLocation At)1770e8d8bef9SDimitry Andric bool shouldAnalyzeCalledOnceImpl(llvm::ArrayRef<unsigned> DiagIDs,
1771e8d8bef9SDimitry Andric                                  const DiagnosticsEngine &Diags,
1772e8d8bef9SDimitry Andric                                  SourceLocation At) {
1773e8d8bef9SDimitry Andric   return llvm::any_of(DiagIDs, [&Diags, At](unsigned DiagID) {
1774e8d8bef9SDimitry Andric     return !Diags.isIgnored(DiagID, At);
1775e8d8bef9SDimitry Andric   });
1776e8d8bef9SDimitry Andric }
1777e8d8bef9SDimitry Andric 
shouldAnalyzeCalledOnceConventions(const DiagnosticsEngine & Diags,SourceLocation At)1778e8d8bef9SDimitry Andric bool shouldAnalyzeCalledOnceConventions(const DiagnosticsEngine &Diags,
1779e8d8bef9SDimitry Andric                                         SourceLocation At) {
1780e8d8bef9SDimitry Andric   return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);
1781e8d8bef9SDimitry Andric }
1782e8d8bef9SDimitry Andric 
shouldAnalyzeCalledOnceParameters(const DiagnosticsEngine & Diags,SourceLocation At)1783e8d8bef9SDimitry Andric bool shouldAnalyzeCalledOnceParameters(const DiagnosticsEngine &Diags,
1784e8d8bef9SDimitry Andric                                        SourceLocation At) {
1785e8d8bef9SDimitry Andric   return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||
1786e8d8bef9SDimitry Andric          shouldAnalyzeCalledOnceConventions(Diags, At);
1787e8d8bef9SDimitry Andric }
17880b57cec5SDimitry Andric } // anonymous namespace
17890b57cec5SDimitry Andric 
17900b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
17910b57cec5SDimitry Andric // -Wthread-safety
17920b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
17930b57cec5SDimitry Andric namespace clang {
17940b57cec5SDimitry Andric namespace threadSafety {
17950b57cec5SDimitry Andric namespace {
17960b57cec5SDimitry Andric class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
17970b57cec5SDimitry Andric   Sema &S;
17980b57cec5SDimitry Andric   DiagList Warnings;
17990b57cec5SDimitry Andric   SourceLocation FunLocation, FunEndLocation;
18000b57cec5SDimitry Andric 
18010b57cec5SDimitry Andric   const FunctionDecl *CurrentFunction;
18020b57cec5SDimitry Andric   bool Verbose;
18030b57cec5SDimitry Andric 
getNotes() const18040b57cec5SDimitry Andric   OptionalNotes getNotes() const {
18050b57cec5SDimitry Andric     if (Verbose && CurrentFunction) {
18060b57cec5SDimitry Andric       PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(),
18070b57cec5SDimitry Andric                                 S.PDiag(diag::note_thread_warning_in_fun)
18080b57cec5SDimitry Andric                                     << CurrentFunction);
18090b57cec5SDimitry Andric       return OptionalNotes(1, FNote);
18100b57cec5SDimitry Andric     }
18110b57cec5SDimitry Andric     return OptionalNotes();
18120b57cec5SDimitry Andric   }
18130b57cec5SDimitry Andric 
getNotes(const PartialDiagnosticAt & Note) const18140b57cec5SDimitry Andric   OptionalNotes getNotes(const PartialDiagnosticAt &Note) const {
18150b57cec5SDimitry Andric     OptionalNotes ONS(1, Note);
18160b57cec5SDimitry Andric     if (Verbose && CurrentFunction) {
18170b57cec5SDimitry Andric       PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(),
18180b57cec5SDimitry Andric                                 S.PDiag(diag::note_thread_warning_in_fun)
18190b57cec5SDimitry Andric                                     << CurrentFunction);
18200b57cec5SDimitry Andric       ONS.push_back(std::move(FNote));
18210b57cec5SDimitry Andric     }
18220b57cec5SDimitry Andric     return ONS;
18230b57cec5SDimitry Andric   }
18240b57cec5SDimitry Andric 
getNotes(const PartialDiagnosticAt & Note1,const PartialDiagnosticAt & Note2) const18250b57cec5SDimitry Andric   OptionalNotes getNotes(const PartialDiagnosticAt &Note1,
18260b57cec5SDimitry Andric                          const PartialDiagnosticAt &Note2) const {
18270b57cec5SDimitry Andric     OptionalNotes ONS;
18280b57cec5SDimitry Andric     ONS.push_back(Note1);
18290b57cec5SDimitry Andric     ONS.push_back(Note2);
18300b57cec5SDimitry Andric     if (Verbose && CurrentFunction) {
18310b57cec5SDimitry Andric       PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(),
18320b57cec5SDimitry Andric                                 S.PDiag(diag::note_thread_warning_in_fun)
18330b57cec5SDimitry Andric                                     << CurrentFunction);
18340b57cec5SDimitry Andric       ONS.push_back(std::move(FNote));
18350b57cec5SDimitry Andric     }
18360b57cec5SDimitry Andric     return ONS;
18370b57cec5SDimitry Andric   }
18380b57cec5SDimitry Andric 
makeLockedHereNote(SourceLocation LocLocked,StringRef Kind)18390b57cec5SDimitry Andric   OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) {
18400b57cec5SDimitry Andric     return LocLocked.isValid()
18410b57cec5SDimitry Andric                ? getNotes(PartialDiagnosticAt(
18420b57cec5SDimitry Andric                      LocLocked, S.PDiag(diag::note_locked_here) << Kind))
18430b57cec5SDimitry Andric                : getNotes();
18440b57cec5SDimitry Andric   }
18450b57cec5SDimitry Andric 
makeUnlockedHereNote(SourceLocation LocUnlocked,StringRef Kind)18465ffd83dbSDimitry Andric   OptionalNotes makeUnlockedHereNote(SourceLocation LocUnlocked,
18475ffd83dbSDimitry Andric                                      StringRef Kind) {
18485ffd83dbSDimitry Andric     return LocUnlocked.isValid()
18495ffd83dbSDimitry Andric                ? getNotes(PartialDiagnosticAt(
18505ffd83dbSDimitry Andric                      LocUnlocked, S.PDiag(diag::note_unlocked_here) << Kind))
18515ffd83dbSDimitry Andric                : getNotes();
18525ffd83dbSDimitry Andric   }
18535ffd83dbSDimitry Andric 
18540b57cec5SDimitry Andric  public:
ThreadSafetyReporter(Sema & S,SourceLocation FL,SourceLocation FEL)18550b57cec5SDimitry Andric   ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
18560b57cec5SDimitry Andric     : S(S), FunLocation(FL), FunEndLocation(FEL),
18570b57cec5SDimitry Andric       CurrentFunction(nullptr), Verbose(false) {}
18580b57cec5SDimitry Andric 
setVerbose(bool b)18590b57cec5SDimitry Andric   void setVerbose(bool b) { Verbose = b; }
18600b57cec5SDimitry Andric 
18610b57cec5SDimitry Andric   /// Emit all buffered diagnostics in order of sourcelocation.
18620b57cec5SDimitry Andric   /// We need to output diagnostics produced while iterating through
18630b57cec5SDimitry Andric   /// the lockset in deterministic order, so this function orders diagnostics
18640b57cec5SDimitry Andric   /// and outputs them.
emitDiagnostics()18650b57cec5SDimitry Andric   void emitDiagnostics() {
18660b57cec5SDimitry Andric     Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
18670b57cec5SDimitry Andric     for (const auto &Diag : Warnings) {
18680b57cec5SDimitry Andric       S.Diag(Diag.first.first, Diag.first.second);
18690b57cec5SDimitry Andric       for (const auto &Note : Diag.second)
18700b57cec5SDimitry Andric         S.Diag(Note.first, Note.second);
18710b57cec5SDimitry Andric     }
18720b57cec5SDimitry Andric   }
18730b57cec5SDimitry Andric 
handleInvalidLockExp(SourceLocation Loc)187481ad6265SDimitry Andric   void handleInvalidLockExp(SourceLocation Loc) override {
18750b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_cannot_resolve_lock)
18760b57cec5SDimitry Andric                                          << Loc);
18770b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning), getNotes());
18780b57cec5SDimitry Andric   }
18790b57cec5SDimitry Andric 
handleUnmatchedUnlock(StringRef Kind,Name LockName,SourceLocation Loc,SourceLocation LocPreviousUnlock)18805ffd83dbSDimitry Andric   void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc,
18815ffd83dbSDimitry Andric                              SourceLocation LocPreviousUnlock) override {
18820b57cec5SDimitry Andric     if (Loc.isInvalid())
18830b57cec5SDimitry Andric       Loc = FunLocation;
18840b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_but_no_lock)
18850b57cec5SDimitry Andric                                          << Kind << LockName);
18865ffd83dbSDimitry Andric     Warnings.emplace_back(std::move(Warning),
18875ffd83dbSDimitry Andric                           makeUnlockedHereNote(LocPreviousUnlock, Kind));
18880b57cec5SDimitry Andric   }
18890b57cec5SDimitry Andric 
handleIncorrectUnlockKind(StringRef Kind,Name LockName,LockKind Expected,LockKind Received,SourceLocation LocLocked,SourceLocation LocUnlock)18900b57cec5SDimitry Andric   void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
18910b57cec5SDimitry Andric                                  LockKind Expected, LockKind Received,
18920b57cec5SDimitry Andric                                  SourceLocation LocLocked,
18930b57cec5SDimitry Andric                                  SourceLocation LocUnlock) override {
18940b57cec5SDimitry Andric     if (LocUnlock.isInvalid())
18950b57cec5SDimitry Andric       LocUnlock = FunLocation;
18960b57cec5SDimitry Andric     PartialDiagnosticAt Warning(
18970b57cec5SDimitry Andric         LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch)
18980b57cec5SDimitry Andric                        << Kind << LockName << Received << Expected);
18990b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning),
19000b57cec5SDimitry Andric                           makeLockedHereNote(LocLocked, Kind));
19010b57cec5SDimitry Andric   }
19020b57cec5SDimitry Andric 
handleDoubleLock(StringRef Kind,Name LockName,SourceLocation LocLocked,SourceLocation LocDoubleLock)19030b57cec5SDimitry Andric   void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked,
19040b57cec5SDimitry Andric                         SourceLocation LocDoubleLock) override {
19050b57cec5SDimitry Andric     if (LocDoubleLock.isInvalid())
19060b57cec5SDimitry Andric       LocDoubleLock = FunLocation;
19070b57cec5SDimitry Andric     PartialDiagnosticAt Warning(LocDoubleLock, S.PDiag(diag::warn_double_lock)
19080b57cec5SDimitry Andric                                                    << Kind << LockName);
19090b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning),
19100b57cec5SDimitry Andric                           makeLockedHereNote(LocLocked, Kind));
19110b57cec5SDimitry Andric   }
19120b57cec5SDimitry Andric 
handleMutexHeldEndOfScope(StringRef Kind,Name LockName,SourceLocation LocLocked,SourceLocation LocEndOfScope,LockErrorKind LEK)19130b57cec5SDimitry Andric   void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
19140b57cec5SDimitry Andric                                  SourceLocation LocLocked,
19150b57cec5SDimitry Andric                                  SourceLocation LocEndOfScope,
19160b57cec5SDimitry Andric                                  LockErrorKind LEK) override {
19170b57cec5SDimitry Andric     unsigned DiagID = 0;
19180b57cec5SDimitry Andric     switch (LEK) {
19190b57cec5SDimitry Andric       case LEK_LockedSomePredecessors:
19200b57cec5SDimitry Andric         DiagID = diag::warn_lock_some_predecessors;
19210b57cec5SDimitry Andric         break;
19220b57cec5SDimitry Andric       case LEK_LockedSomeLoopIterations:
19230b57cec5SDimitry Andric         DiagID = diag::warn_expecting_lock_held_on_loop;
19240b57cec5SDimitry Andric         break;
19250b57cec5SDimitry Andric       case LEK_LockedAtEndOfFunction:
19260b57cec5SDimitry Andric         DiagID = diag::warn_no_unlock;
19270b57cec5SDimitry Andric         break;
19280b57cec5SDimitry Andric       case LEK_NotLockedAtEndOfFunction:
19290b57cec5SDimitry Andric         DiagID = diag::warn_expecting_locked;
19300b57cec5SDimitry Andric         break;
19310b57cec5SDimitry Andric     }
19320b57cec5SDimitry Andric     if (LocEndOfScope.isInvalid())
19330b57cec5SDimitry Andric       LocEndOfScope = FunEndLocation;
19340b57cec5SDimitry Andric 
19350b57cec5SDimitry Andric     PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << Kind
19360b57cec5SDimitry Andric                                                                << LockName);
19370b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning),
19380b57cec5SDimitry Andric                           makeLockedHereNote(LocLocked, Kind));
19390b57cec5SDimitry Andric   }
19400b57cec5SDimitry Andric 
handleExclusiveAndShared(StringRef Kind,Name LockName,SourceLocation Loc1,SourceLocation Loc2)19410b57cec5SDimitry Andric   void handleExclusiveAndShared(StringRef Kind, Name LockName,
19420b57cec5SDimitry Andric                                 SourceLocation Loc1,
19430b57cec5SDimitry Andric                                 SourceLocation Loc2) override {
19440b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc1,
19450b57cec5SDimitry Andric                                 S.PDiag(diag::warn_lock_exclusive_and_shared)
19460b57cec5SDimitry Andric                                     << Kind << LockName);
19470b57cec5SDimitry Andric     PartialDiagnosticAt Note(Loc2, S.PDiag(diag::note_lock_exclusive_and_shared)
19480b57cec5SDimitry Andric                                        << Kind << LockName);
19490b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning), getNotes(Note));
19500b57cec5SDimitry Andric   }
19510b57cec5SDimitry Andric 
handleNoMutexHeld(const NamedDecl * D,ProtectedOperationKind POK,AccessKind AK,SourceLocation Loc)195281ad6265SDimitry Andric   void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK,
195381ad6265SDimitry Andric                          AccessKind AK, SourceLocation Loc) override {
19540b57cec5SDimitry Andric     assert((POK == POK_VarAccess || POK == POK_VarDereference) &&
19550b57cec5SDimitry Andric            "Only works for variables");
19560b57cec5SDimitry Andric     unsigned DiagID = POK == POK_VarAccess?
19570b57cec5SDimitry Andric                         diag::warn_variable_requires_any_lock:
19580b57cec5SDimitry Andric                         diag::warn_var_deref_requires_any_lock;
19590b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
19600b57cec5SDimitry Andric       << D << getLockKindFromAccessKind(AK));
19610b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning), getNotes());
19620b57cec5SDimitry Andric   }
19630b57cec5SDimitry Andric 
handleMutexNotHeld(StringRef Kind,const NamedDecl * D,ProtectedOperationKind POK,Name LockName,LockKind LK,SourceLocation Loc,Name * PossibleMatch)19640b57cec5SDimitry Andric   void handleMutexNotHeld(StringRef Kind, const NamedDecl *D,
19650b57cec5SDimitry Andric                           ProtectedOperationKind POK, Name LockName,
19660b57cec5SDimitry Andric                           LockKind LK, SourceLocation Loc,
19670b57cec5SDimitry Andric                           Name *PossibleMatch) override {
19680b57cec5SDimitry Andric     unsigned DiagID = 0;
19690b57cec5SDimitry Andric     if (PossibleMatch) {
19700b57cec5SDimitry Andric       switch (POK) {
19710b57cec5SDimitry Andric         case POK_VarAccess:
19720b57cec5SDimitry Andric           DiagID = diag::warn_variable_requires_lock_precise;
19730b57cec5SDimitry Andric           break;
19740b57cec5SDimitry Andric         case POK_VarDereference:
19750b57cec5SDimitry Andric           DiagID = diag::warn_var_deref_requires_lock_precise;
19760b57cec5SDimitry Andric           break;
19770b57cec5SDimitry Andric         case POK_FunctionCall:
19780b57cec5SDimitry Andric           DiagID = diag::warn_fun_requires_lock_precise;
19790b57cec5SDimitry Andric           break;
19800b57cec5SDimitry Andric         case POK_PassByRef:
19810b57cec5SDimitry Andric           DiagID = diag::warn_guarded_pass_by_reference;
19820b57cec5SDimitry Andric           break;
19830b57cec5SDimitry Andric         case POK_PtPassByRef:
19840b57cec5SDimitry Andric           DiagID = diag::warn_pt_guarded_pass_by_reference;
19850b57cec5SDimitry Andric           break;
19865f757f3fSDimitry Andric         case POK_ReturnByRef:
19875f757f3fSDimitry Andric           DiagID = diag::warn_guarded_return_by_reference;
19885f757f3fSDimitry Andric           break;
19895f757f3fSDimitry Andric         case POK_PtReturnByRef:
19905f757f3fSDimitry Andric           DiagID = diag::warn_pt_guarded_return_by_reference;
19915f757f3fSDimitry Andric           break;
19920b57cec5SDimitry Andric       }
19930b57cec5SDimitry Andric       PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind
19940b57cec5SDimitry Andric                                                        << D
19950b57cec5SDimitry Andric                                                        << LockName << LK);
19960b57cec5SDimitry Andric       PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match)
19970b57cec5SDimitry Andric                                         << *PossibleMatch);
19980b57cec5SDimitry Andric       if (Verbose && POK == POK_VarAccess) {
19990b57cec5SDimitry Andric         PartialDiagnosticAt VNote(D->getLocation(),
20000b57cec5SDimitry Andric                                   S.PDiag(diag::note_guarded_by_declared_here)
2001e8d8bef9SDimitry Andric                                       << D->getDeclName());
20020b57cec5SDimitry Andric         Warnings.emplace_back(std::move(Warning), getNotes(Note, VNote));
20030b57cec5SDimitry Andric       } else
20040b57cec5SDimitry Andric         Warnings.emplace_back(std::move(Warning), getNotes(Note));
20050b57cec5SDimitry Andric     } else {
20060b57cec5SDimitry Andric       switch (POK) {
20070b57cec5SDimitry Andric         case POK_VarAccess:
20080b57cec5SDimitry Andric           DiagID = diag::warn_variable_requires_lock;
20090b57cec5SDimitry Andric           break;
20100b57cec5SDimitry Andric         case POK_VarDereference:
20110b57cec5SDimitry Andric           DiagID = diag::warn_var_deref_requires_lock;
20120b57cec5SDimitry Andric           break;
20130b57cec5SDimitry Andric         case POK_FunctionCall:
20140b57cec5SDimitry Andric           DiagID = diag::warn_fun_requires_lock;
20150b57cec5SDimitry Andric           break;
20160b57cec5SDimitry Andric         case POK_PassByRef:
20170b57cec5SDimitry Andric           DiagID = diag::warn_guarded_pass_by_reference;
20180b57cec5SDimitry Andric           break;
20190b57cec5SDimitry Andric         case POK_PtPassByRef:
20200b57cec5SDimitry Andric           DiagID = diag::warn_pt_guarded_pass_by_reference;
20210b57cec5SDimitry Andric           break;
20225f757f3fSDimitry Andric         case POK_ReturnByRef:
20235f757f3fSDimitry Andric           DiagID = diag::warn_guarded_return_by_reference;
20245f757f3fSDimitry Andric           break;
20255f757f3fSDimitry Andric         case POK_PtReturnByRef:
20265f757f3fSDimitry Andric           DiagID = diag::warn_pt_guarded_return_by_reference;
20275f757f3fSDimitry Andric           break;
20280b57cec5SDimitry Andric       }
20290b57cec5SDimitry Andric       PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind
20300b57cec5SDimitry Andric                                                        << D
20310b57cec5SDimitry Andric                                                        << LockName << LK);
20320b57cec5SDimitry Andric       if (Verbose && POK == POK_VarAccess) {
20330b57cec5SDimitry Andric         PartialDiagnosticAt Note(D->getLocation(),
20340b57cec5SDimitry Andric                                  S.PDiag(diag::note_guarded_by_declared_here));
20350b57cec5SDimitry Andric         Warnings.emplace_back(std::move(Warning), getNotes(Note));
20360b57cec5SDimitry Andric       } else
20370b57cec5SDimitry Andric         Warnings.emplace_back(std::move(Warning), getNotes());
20380b57cec5SDimitry Andric     }
20390b57cec5SDimitry Andric   }
20400b57cec5SDimitry Andric 
handleNegativeNotHeld(StringRef Kind,Name LockName,Name Neg,SourceLocation Loc)20410b57cec5SDimitry Andric   void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
20420b57cec5SDimitry Andric                              SourceLocation Loc) override {
20430b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc,
20440b57cec5SDimitry Andric         S.PDiag(diag::warn_acquire_requires_negative_cap)
20450b57cec5SDimitry Andric         << Kind << LockName << Neg);
20460b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning), getNotes());
20470b57cec5SDimitry Andric   }
20480b57cec5SDimitry Andric 
handleNegativeNotHeld(const NamedDecl * D,Name LockName,SourceLocation Loc)2049e8d8bef9SDimitry Andric   void handleNegativeNotHeld(const NamedDecl *D, Name LockName,
2050e8d8bef9SDimitry Andric                              SourceLocation Loc) override {
2051e8d8bef9SDimitry Andric     PartialDiagnosticAt Warning(
2052e8d8bef9SDimitry Andric         Loc, S.PDiag(diag::warn_fun_requires_negative_cap) << D << LockName);
2053e8d8bef9SDimitry Andric     Warnings.emplace_back(std::move(Warning), getNotes());
2054e8d8bef9SDimitry Andric   }
2055e8d8bef9SDimitry Andric 
handleFunExcludesLock(StringRef Kind,Name FunName,Name LockName,SourceLocation Loc)20560b57cec5SDimitry Andric   void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
20570b57cec5SDimitry Andric                              SourceLocation Loc) override {
20580b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_fun_excludes_mutex)
20590b57cec5SDimitry Andric                                          << Kind << FunName << LockName);
20600b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning), getNotes());
20610b57cec5SDimitry Andric   }
20620b57cec5SDimitry Andric 
handleLockAcquiredBefore(StringRef Kind,Name L1Name,Name L2Name,SourceLocation Loc)20630b57cec5SDimitry Andric   void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
20640b57cec5SDimitry Andric                                 SourceLocation Loc) override {
20650b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc,
20660b57cec5SDimitry Andric       S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
20670b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning), getNotes());
20680b57cec5SDimitry Andric   }
20690b57cec5SDimitry Andric 
handleBeforeAfterCycle(Name L1Name,SourceLocation Loc)20700b57cec5SDimitry Andric   void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) override {
20710b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc,
20720b57cec5SDimitry Andric       S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
20730b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning), getNotes());
20740b57cec5SDimitry Andric   }
20750b57cec5SDimitry Andric 
enterFunction(const FunctionDecl * FD)20760b57cec5SDimitry Andric   void enterFunction(const FunctionDecl* FD) override {
20770b57cec5SDimitry Andric     CurrentFunction = FD;
20780b57cec5SDimitry Andric   }
20790b57cec5SDimitry Andric 
leaveFunction(const FunctionDecl * FD)20800b57cec5SDimitry Andric   void leaveFunction(const FunctionDecl* FD) override {
20810b57cec5SDimitry Andric     CurrentFunction = nullptr;
20820b57cec5SDimitry Andric   }
20830b57cec5SDimitry Andric };
20840b57cec5SDimitry Andric } // anonymous namespace
20850b57cec5SDimitry Andric } // namespace threadSafety
20860b57cec5SDimitry Andric } // namespace clang
20870b57cec5SDimitry Andric 
20880b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
20890b57cec5SDimitry Andric // -Wconsumed
20900b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
20910b57cec5SDimitry Andric 
20920b57cec5SDimitry Andric namespace clang {
20930b57cec5SDimitry Andric namespace consumed {
20940b57cec5SDimitry Andric namespace {
20950b57cec5SDimitry Andric class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
20960b57cec5SDimitry Andric 
20970b57cec5SDimitry Andric   Sema &S;
20980b57cec5SDimitry Andric   DiagList Warnings;
20990b57cec5SDimitry Andric 
21000b57cec5SDimitry Andric public:
21010b57cec5SDimitry Andric 
ConsumedWarningsHandler(Sema & S)21020b57cec5SDimitry Andric   ConsumedWarningsHandler(Sema &S) : S(S) {}
21030b57cec5SDimitry Andric 
emitDiagnostics()21040b57cec5SDimitry Andric   void emitDiagnostics() override {
21050b57cec5SDimitry Andric     Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
21060b57cec5SDimitry Andric     for (const auto &Diag : Warnings) {
21070b57cec5SDimitry Andric       S.Diag(Diag.first.first, Diag.first.second);
21080b57cec5SDimitry Andric       for (const auto &Note : Diag.second)
21090b57cec5SDimitry Andric         S.Diag(Note.first, Note.second);
21100b57cec5SDimitry Andric     }
21110b57cec5SDimitry Andric   }
21120b57cec5SDimitry Andric 
warnLoopStateMismatch(SourceLocation Loc,StringRef VariableName)21130b57cec5SDimitry Andric   void warnLoopStateMismatch(SourceLocation Loc,
21140b57cec5SDimitry Andric                              StringRef VariableName) override {
21150b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch) <<
21160b57cec5SDimitry Andric       VariableName);
21170b57cec5SDimitry Andric 
21180b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning), OptionalNotes());
21190b57cec5SDimitry Andric   }
21200b57cec5SDimitry Andric 
warnParamReturnTypestateMismatch(SourceLocation Loc,StringRef VariableName,StringRef ExpectedState,StringRef ObservedState)21210b57cec5SDimitry Andric   void warnParamReturnTypestateMismatch(SourceLocation Loc,
21220b57cec5SDimitry Andric                                         StringRef VariableName,
21230b57cec5SDimitry Andric                                         StringRef ExpectedState,
21240b57cec5SDimitry Andric                                         StringRef ObservedState) override {
21250b57cec5SDimitry Andric 
21260b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc, S.PDiag(
21270b57cec5SDimitry Andric       diag::warn_param_return_typestate_mismatch) << VariableName <<
21280b57cec5SDimitry Andric         ExpectedState << ObservedState);
21290b57cec5SDimitry Andric 
21300b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning), OptionalNotes());
21310b57cec5SDimitry Andric   }
21320b57cec5SDimitry Andric 
warnParamTypestateMismatch(SourceLocation Loc,StringRef ExpectedState,StringRef ObservedState)21330b57cec5SDimitry Andric   void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
21340b57cec5SDimitry Andric                                   StringRef ObservedState) override {
21350b57cec5SDimitry Andric 
21360b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc, S.PDiag(
21370b57cec5SDimitry Andric       diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
21380b57cec5SDimitry Andric 
21390b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning), OptionalNotes());
21400b57cec5SDimitry Andric   }
21410b57cec5SDimitry Andric 
warnReturnTypestateForUnconsumableType(SourceLocation Loc,StringRef TypeName)21420b57cec5SDimitry Andric   void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
21430b57cec5SDimitry Andric                                               StringRef TypeName) override {
21440b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc, S.PDiag(
21450b57cec5SDimitry Andric       diag::warn_return_typestate_for_unconsumable_type) << TypeName);
21460b57cec5SDimitry Andric 
21470b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning), OptionalNotes());
21480b57cec5SDimitry Andric   }
21490b57cec5SDimitry Andric 
warnReturnTypestateMismatch(SourceLocation Loc,StringRef ExpectedState,StringRef ObservedState)21500b57cec5SDimitry Andric   void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
21510b57cec5SDimitry Andric                                    StringRef ObservedState) override {
21520b57cec5SDimitry Andric 
21530b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc, S.PDiag(
21540b57cec5SDimitry Andric       diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
21550b57cec5SDimitry Andric 
21560b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning), OptionalNotes());
21570b57cec5SDimitry Andric   }
21580b57cec5SDimitry Andric 
warnUseOfTempInInvalidState(StringRef MethodName,StringRef State,SourceLocation Loc)21590b57cec5SDimitry Andric   void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
21600b57cec5SDimitry Andric                                    SourceLocation Loc) override {
21610b57cec5SDimitry Andric 
21620b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc, S.PDiag(
21630b57cec5SDimitry Andric       diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
21640b57cec5SDimitry Andric 
21650b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning), OptionalNotes());
21660b57cec5SDimitry Andric   }
21670b57cec5SDimitry Andric 
warnUseInInvalidState(StringRef MethodName,StringRef VariableName,StringRef State,SourceLocation Loc)21680b57cec5SDimitry Andric   void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
21690b57cec5SDimitry Andric                              StringRef State, SourceLocation Loc) override {
21700b57cec5SDimitry Andric 
21710b57cec5SDimitry Andric     PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) <<
21720b57cec5SDimitry Andric                                 MethodName << VariableName << State);
21730b57cec5SDimitry Andric 
21740b57cec5SDimitry Andric     Warnings.emplace_back(std::move(Warning), OptionalNotes());
21750b57cec5SDimitry Andric   }
21760b57cec5SDimitry Andric };
21770b57cec5SDimitry Andric } // anonymous namespace
21780b57cec5SDimitry Andric } // namespace consumed
21790b57cec5SDimitry Andric } // namespace clang
21800b57cec5SDimitry Andric 
21810b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2182bdd1243dSDimitry Andric // Unsafe buffer usage analysis.
2183bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
2184bdd1243dSDimitry Andric 
2185bdd1243dSDimitry Andric namespace {
2186bdd1243dSDimitry Andric class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
2187bdd1243dSDimitry Andric   Sema &S;
218806c3fb27SDimitry Andric   bool SuggestSuggestions;  // Recommend -fsafe-buffer-usage-suggestions?
2189bdd1243dSDimitry Andric 
21905f757f3fSDimitry Andric   // Lists as a string the names of variables in `VarGroupForVD` except for `VD`
21915f757f3fSDimitry Andric   // itself:
listVariableGroupAsString(const VarDecl * VD,const ArrayRef<const VarDecl * > & VarGroupForVD) const21925f757f3fSDimitry Andric   std::string listVariableGroupAsString(
21935f757f3fSDimitry Andric       const VarDecl *VD, const ArrayRef<const VarDecl *> &VarGroupForVD) const {
21945f757f3fSDimitry Andric     if (VarGroupForVD.size() <= 1)
21955f757f3fSDimitry Andric       return "";
21965f757f3fSDimitry Andric 
21975f757f3fSDimitry Andric     std::vector<StringRef> VarNames;
21985f757f3fSDimitry Andric     auto PutInQuotes = [](StringRef S) -> std::string {
21995f757f3fSDimitry Andric       return "'" + S.str() + "'";
22005f757f3fSDimitry Andric     };
22015f757f3fSDimitry Andric 
22025f757f3fSDimitry Andric     for (auto *V : VarGroupForVD) {
22035f757f3fSDimitry Andric       if (V == VD)
22045f757f3fSDimitry Andric         continue;
22055f757f3fSDimitry Andric       VarNames.push_back(V->getName());
22065f757f3fSDimitry Andric     }
22075f757f3fSDimitry Andric     if (VarNames.size() == 1) {
22085f757f3fSDimitry Andric       return PutInQuotes(VarNames[0]);
22095f757f3fSDimitry Andric     }
22105f757f3fSDimitry Andric     if (VarNames.size() == 2) {
22115f757f3fSDimitry Andric       return PutInQuotes(VarNames[0]) + " and " + PutInQuotes(VarNames[1]);
22125f757f3fSDimitry Andric     }
22135f757f3fSDimitry Andric     assert(VarGroupForVD.size() > 3);
22145f757f3fSDimitry Andric     const unsigned N = VarNames.size() -
22155f757f3fSDimitry Andric                        2; // need to print the last two names as "..., X, and Y"
22165f757f3fSDimitry Andric     std::string AllVars = "";
22175f757f3fSDimitry Andric 
22185f757f3fSDimitry Andric     for (unsigned I = 0; I < N; ++I)
22195f757f3fSDimitry Andric       AllVars.append(PutInQuotes(VarNames[I]) + ", ");
22205f757f3fSDimitry Andric     AllVars.append(PutInQuotes(VarNames[N]) + ", and " +
22215f757f3fSDimitry Andric                    PutInQuotes(VarNames[N + 1]));
22225f757f3fSDimitry Andric     return AllVars;
22235f757f3fSDimitry Andric   }
22245f757f3fSDimitry Andric 
2225bdd1243dSDimitry Andric public:
UnsafeBufferUsageReporter(Sema & S,bool SuggestSuggestions)222606c3fb27SDimitry Andric   UnsafeBufferUsageReporter(Sema &S, bool SuggestSuggestions)
222706c3fb27SDimitry Andric     : S(S), SuggestSuggestions(SuggestSuggestions) {}
2228bdd1243dSDimitry Andric 
handleUnsafeOperation(const Stmt * Operation,bool IsRelatedToDecl,ASTContext & Ctx)22291db9f3b2SDimitry Andric   void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl,
22301db9f3b2SDimitry Andric                              ASTContext &Ctx) override {
2231bdd1243dSDimitry Andric     SourceLocation Loc;
2232bdd1243dSDimitry Andric     SourceRange Range;
2233bdd1243dSDimitry Andric     unsigned MsgParam = 0;
2234bdd1243dSDimitry Andric     if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
2235bdd1243dSDimitry Andric       Loc = ASE->getBase()->getExprLoc();
2236bdd1243dSDimitry Andric       Range = ASE->getBase()->getSourceRange();
2237bdd1243dSDimitry Andric       MsgParam = 2;
2238bdd1243dSDimitry Andric     } else if (const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
2239bdd1243dSDimitry Andric       BinaryOperator::Opcode Op = BO->getOpcode();
2240bdd1243dSDimitry Andric       if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
2241bdd1243dSDimitry Andric           Op == BO_SubAssign) {
2242bdd1243dSDimitry Andric         if (BO->getRHS()->getType()->isIntegerType()) {
2243bdd1243dSDimitry Andric           Loc = BO->getLHS()->getExprLoc();
2244bdd1243dSDimitry Andric           Range = BO->getLHS()->getSourceRange();
2245bdd1243dSDimitry Andric         } else {
2246bdd1243dSDimitry Andric           Loc = BO->getRHS()->getExprLoc();
2247bdd1243dSDimitry Andric           Range = BO->getRHS()->getSourceRange();
2248bdd1243dSDimitry Andric         }
2249bdd1243dSDimitry Andric         MsgParam = 1;
2250bdd1243dSDimitry Andric       }
2251bdd1243dSDimitry Andric     } else if (const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
2252bdd1243dSDimitry Andric       UnaryOperator::Opcode Op = UO->getOpcode();
2253bdd1243dSDimitry Andric       if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
2254bdd1243dSDimitry Andric           Op == UO_PostDec) {
2255bdd1243dSDimitry Andric         Loc = UO->getSubExpr()->getExprLoc();
2256bdd1243dSDimitry Andric         Range = UO->getSubExpr()->getSourceRange();
2257bdd1243dSDimitry Andric         MsgParam = 1;
2258bdd1243dSDimitry Andric       }
2259bdd1243dSDimitry Andric     } else {
2260*0fca6ea1SDimitry Andric       if (isa<CallExpr>(Operation) || isa<CXXConstructExpr>(Operation)) {
226106c3fb27SDimitry Andric         // note_unsafe_buffer_operation doesn't have this mode yet.
226206c3fb27SDimitry Andric         assert(!IsRelatedToDecl && "Not implemented yet!");
226306c3fb27SDimitry Andric         MsgParam = 3;
22641db9f3b2SDimitry Andric       } else if (const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) {
22651db9f3b2SDimitry Andric         QualType destType = ECE->getType();
22667a6dacacSDimitry Andric         if (!isa<PointerType>(destType))
22677a6dacacSDimitry Andric           return;
22687a6dacacSDimitry Andric 
22691db9f3b2SDimitry Andric         const uint64_t dSize =
22701db9f3b2SDimitry Andric             Ctx.getTypeSize(destType.getTypePtr()->getPointeeType());
22717a6dacacSDimitry Andric 
22727a6dacacSDimitry Andric         QualType srcType = ECE->getSubExpr()->getType();
22731db9f3b2SDimitry Andric         const uint64_t sSize =
22741db9f3b2SDimitry Andric             Ctx.getTypeSize(srcType.getTypePtr()->getPointeeType());
22751db9f3b2SDimitry Andric         if (sSize >= dSize)
22761db9f3b2SDimitry Andric           return;
22777a6dacacSDimitry Andric 
22781db9f3b2SDimitry Andric         MsgParam = 4;
227906c3fb27SDimitry Andric       }
2280bdd1243dSDimitry Andric       Loc = Operation->getBeginLoc();
2281bdd1243dSDimitry Andric       Range = Operation->getSourceRange();
2282bdd1243dSDimitry Andric     }
228306c3fb27SDimitry Andric     if (IsRelatedToDecl) {
228406c3fb27SDimitry Andric       assert(!SuggestSuggestions &&
228506c3fb27SDimitry Andric              "Variables blamed for unsafe buffer usage without suggestions!");
2286bdd1243dSDimitry Andric       S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;
228706c3fb27SDimitry Andric     } else {
2288bdd1243dSDimitry Andric       S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam << Range;
228906c3fb27SDimitry Andric       if (SuggestSuggestions) {
229006c3fb27SDimitry Andric         S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled);
229106c3fb27SDimitry Andric       }
229206c3fb27SDimitry Andric     }
2293bdd1243dSDimitry Andric   }
2294bdd1243dSDimitry Andric 
handleUnsafeOperationInContainer(const Stmt * Operation,bool IsRelatedToDecl,ASTContext & Ctx)2295*0fca6ea1SDimitry Andric   void handleUnsafeOperationInContainer(const Stmt *Operation,
2296*0fca6ea1SDimitry Andric                                         bool IsRelatedToDecl,
2297*0fca6ea1SDimitry Andric                                         ASTContext &Ctx) override {
2298*0fca6ea1SDimitry Andric     SourceLocation Loc;
2299*0fca6ea1SDimitry Andric     SourceRange Range;
2300*0fca6ea1SDimitry Andric     unsigned MsgParam = 0;
2301*0fca6ea1SDimitry Andric 
2302*0fca6ea1SDimitry Andric     // This function only handles SpanTwoParamConstructorGadget so far, which
2303*0fca6ea1SDimitry Andric     // always gives a CXXConstructExpr.
2304*0fca6ea1SDimitry Andric     const auto *CtorExpr = cast<CXXConstructExpr>(Operation);
2305*0fca6ea1SDimitry Andric     Loc = CtorExpr->getLocation();
2306*0fca6ea1SDimitry Andric 
2307*0fca6ea1SDimitry Andric     S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container);
2308*0fca6ea1SDimitry Andric     if (IsRelatedToDecl) {
2309*0fca6ea1SDimitry Andric       assert(!SuggestSuggestions &&
2310*0fca6ea1SDimitry Andric              "Variables blamed for unsafe buffer usage without suggestions!");
2311*0fca6ea1SDimitry Andric       S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;
2312*0fca6ea1SDimitry Andric     }
2313*0fca6ea1SDimitry Andric   }
2314*0fca6ea1SDimitry Andric 
handleUnsafeVariableGroup(const VarDecl * Variable,const VariableGroupsManager & VarGrpMgr,FixItList && Fixes,const Decl * D,const FixitStrategy & VarTargetTypes)231506c3fb27SDimitry Andric   void handleUnsafeVariableGroup(const VarDecl *Variable,
23165f757f3fSDimitry Andric                                  const VariableGroupsManager &VarGrpMgr,
2317*0fca6ea1SDimitry Andric                                  FixItList &&Fixes, const Decl *D,
2318*0fca6ea1SDimitry Andric                                  const FixitStrategy &VarTargetTypes) override {
231906c3fb27SDimitry Andric     assert(!SuggestSuggestions &&
232006c3fb27SDimitry Andric            "Unsafe buffer usage fixits displayed without suggestions!");
232106c3fb27SDimitry Andric     S.Diag(Variable->getLocation(), diag::warn_unsafe_buffer_variable)
232206c3fb27SDimitry Andric         << Variable << (Variable->getType()->isPointerType() ? 0 : 1)
232306c3fb27SDimitry Andric         << Variable->getSourceRange();
232406c3fb27SDimitry Andric     if (!Fixes.empty()) {
23255f757f3fSDimitry Andric       assert(isa<NamedDecl>(D) &&
23265f757f3fSDimitry Andric              "Fix-its are generated only for `NamedDecl`s");
23275f757f3fSDimitry Andric       const NamedDecl *ND = cast<NamedDecl>(D);
23285f757f3fSDimitry Andric       bool BriefMsg = false;
23295f757f3fSDimitry Andric       // If the variable group involves parameters, the diagnostic message will
23305f757f3fSDimitry Andric       // NOT explain how the variables are grouped as the reason is non-trivial
23315f757f3fSDimitry Andric       // and irrelavant to users' experience:
23325f757f3fSDimitry Andric       const auto VarGroupForVD = VarGrpMgr.getGroupOfVar(Variable, &BriefMsg);
2333*0fca6ea1SDimitry Andric       unsigned FixItStrategy = 0;
2334*0fca6ea1SDimitry Andric       switch (VarTargetTypes.lookup(Variable)) {
2335*0fca6ea1SDimitry Andric       case clang::FixitStrategy::Kind::Span:
2336*0fca6ea1SDimitry Andric         FixItStrategy = 0;
2337*0fca6ea1SDimitry Andric         break;
2338*0fca6ea1SDimitry Andric       case clang::FixitStrategy::Kind::Array:
2339*0fca6ea1SDimitry Andric         FixItStrategy = 1;
2340*0fca6ea1SDimitry Andric         break;
2341*0fca6ea1SDimitry Andric       default:
2342*0fca6ea1SDimitry Andric         assert(false && "We support only std::span and std::array");
2343*0fca6ea1SDimitry Andric       };
2344*0fca6ea1SDimitry Andric 
23455f757f3fSDimitry Andric       const auto &FD =
23465f757f3fSDimitry Andric           S.Diag(Variable->getLocation(),
23475f757f3fSDimitry Andric                  BriefMsg ? diag::note_unsafe_buffer_variable_fixit_together
23485f757f3fSDimitry Andric                           : diag::note_unsafe_buffer_variable_fixit_group);
234906c3fb27SDimitry Andric 
235006c3fb27SDimitry Andric       FD << Variable << FixItStrategy;
23515f757f3fSDimitry Andric       FD << listVariableGroupAsString(Variable, VarGroupForVD)
23525f757f3fSDimitry Andric          << (VarGroupForVD.size() > 1) << ND;
23535f757f3fSDimitry Andric       for (const auto &F : Fixes) {
235406c3fb27SDimitry Andric         FD << F;
235506c3fb27SDimitry Andric       }
235606c3fb27SDimitry Andric     }
235706c3fb27SDimitry Andric 
23585f757f3fSDimitry Andric #ifndef NDEBUG
23595f757f3fSDimitry Andric     if (areDebugNotesRequested())
23605f757f3fSDimitry Andric       for (const DebugNote &Note: DebugNotesByVar[Variable])
23615f757f3fSDimitry Andric         S.Diag(Note.first, diag::note_safe_buffer_debug_mode) << Note.second;
23625f757f3fSDimitry Andric #endif
23635f757f3fSDimitry Andric   }
23645f757f3fSDimitry Andric 
isSafeBufferOptOut(const SourceLocation & Loc) const236506c3fb27SDimitry Andric   bool isSafeBufferOptOut(const SourceLocation &Loc) const override {
236606c3fb27SDimitry Andric     return S.PP.isSafeBufferOptOut(S.getSourceManager(), Loc);
236706c3fb27SDimitry Andric   }
236806c3fb27SDimitry Andric 
ignoreUnsafeBufferInContainer(const SourceLocation & Loc) const2369*0fca6ea1SDimitry Andric   bool ignoreUnsafeBufferInContainer(const SourceLocation &Loc) const override {
2370*0fca6ea1SDimitry Andric     return S.Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container, Loc);
2371*0fca6ea1SDimitry Andric   }
2372*0fca6ea1SDimitry Andric 
237306c3fb27SDimitry Andric   // Returns the text representation of clang::unsafe_buffer_usage attribute.
237406c3fb27SDimitry Andric   // `WSSuffix` holds customized "white-space"s, e.g., newline or whilespace
237506c3fb27SDimitry Andric   // characters.
237606c3fb27SDimitry Andric   std::string
getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,StringRef WSSuffix="") const237706c3fb27SDimitry Andric   getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,
237806c3fb27SDimitry Andric                                       StringRef WSSuffix = "") const override {
237906c3fb27SDimitry Andric     Preprocessor &PP = S.getPreprocessor();
238006c3fb27SDimitry Andric     TokenValue ClangUnsafeBufferUsageTokens[] = {
238106c3fb27SDimitry Andric         tok::l_square,
238206c3fb27SDimitry Andric         tok::l_square,
238306c3fb27SDimitry Andric         PP.getIdentifierInfo("clang"),
238406c3fb27SDimitry Andric         tok::coloncolon,
238506c3fb27SDimitry Andric         PP.getIdentifierInfo("unsafe_buffer_usage"),
238606c3fb27SDimitry Andric         tok::r_square,
238706c3fb27SDimitry Andric         tok::r_square};
238806c3fb27SDimitry Andric 
238906c3fb27SDimitry Andric     StringRef MacroName;
239006c3fb27SDimitry Andric 
239106c3fb27SDimitry Andric     // The returned macro (it returns) is guaranteed not to be function-like:
239206c3fb27SDimitry Andric     MacroName = PP.getLastMacroWithSpelling(Loc, ClangUnsafeBufferUsageTokens);
239306c3fb27SDimitry Andric     if (MacroName.empty())
239406c3fb27SDimitry Andric       MacroName = "[[clang::unsafe_buffer_usage]]";
239506c3fb27SDimitry Andric     return MacroName.str() + WSSuffix.str();
2396bdd1243dSDimitry Andric   }
2397bdd1243dSDimitry Andric };
2398bdd1243dSDimitry Andric } // namespace
2399bdd1243dSDimitry Andric 
2400bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
24010b57cec5SDimitry Andric // AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based
24020b57cec5SDimitry Andric //  warnings on a function, method, or block.
24030b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
24040b57cec5SDimitry Andric 
Policy()2405fe6060f1SDimitry Andric sema::AnalysisBasedWarnings::Policy::Policy() {
24060b57cec5SDimitry Andric   enableCheckFallThrough = 1;
24070b57cec5SDimitry Andric   enableCheckUnreachable = 0;
24080b57cec5SDimitry Andric   enableThreadSafetyAnalysis = 0;
24090b57cec5SDimitry Andric   enableConsumedAnalysis = 0;
24100b57cec5SDimitry Andric }
24110b57cec5SDimitry Andric 
2412fe6060f1SDimitry Andric /// InterProceduralData aims to be a storage of whatever data should be passed
2413fe6060f1SDimitry Andric /// between analyses of different functions.
2414fe6060f1SDimitry Andric ///
2415fe6060f1SDimitry Andric /// At the moment, its primary goal is to make the information gathered during
2416fe6060f1SDimitry Andric /// the analysis of the blocks available during the analysis of the enclosing
2417fe6060f1SDimitry Andric /// function.  This is important due to the fact that blocks are analyzed before
2418fe6060f1SDimitry Andric /// the enclosed function is even parsed fully, so it is not viable to access
2419fe6060f1SDimitry Andric /// anything in the outer scope while analyzing the block.  On the other hand,
2420fe6060f1SDimitry Andric /// re-building CFG for blocks and re-analyzing them when we do have all the
2421fe6060f1SDimitry Andric /// information (i.e. during the analysis of the enclosing function) seems to be
2422fe6060f1SDimitry Andric /// ill-designed.
2423fe6060f1SDimitry Andric class sema::AnalysisBasedWarnings::InterProceduralData {
2424fe6060f1SDimitry Andric public:
2425fe6060f1SDimitry Andric   // It is important to analyze blocks within functions because it's a very
2426fe6060f1SDimitry Andric   // common pattern to capture completion handler parameters by blocks.
2427fe6060f1SDimitry Andric   CalledOnceInterProceduralData CalledOnceData;
2428fe6060f1SDimitry Andric };
2429fe6060f1SDimitry Andric 
isEnabled(DiagnosticsEngine & D,unsigned diag)24300b57cec5SDimitry Andric static unsigned isEnabled(DiagnosticsEngine &D, unsigned diag) {
24310b57cec5SDimitry Andric   return (unsigned)!D.isIgnored(diag, SourceLocation());
24320b57cec5SDimitry Andric }
24330b57cec5SDimitry Andric 
AnalysisBasedWarnings(Sema & s)2434fe6060f1SDimitry Andric sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
2435fe6060f1SDimitry Andric     : S(s), IPData(std::make_unique<InterProceduralData>()),
2436fe6060f1SDimitry Andric       NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),
2437fe6060f1SDimitry Andric       MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),
2438fe6060f1SDimitry Andric       NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
24390b57cec5SDimitry Andric       NumUninitAnalysisBlockVisits(0),
24400b57cec5SDimitry Andric       MaxUninitAnalysisBlockVisitsPerFunction(0) {
24410b57cec5SDimitry Andric 
24420b57cec5SDimitry Andric   using namespace diag;
24430b57cec5SDimitry Andric   DiagnosticsEngine &D = S.getDiagnostics();
24440b57cec5SDimitry Andric 
24450b57cec5SDimitry Andric   DefaultPolicy.enableCheckUnreachable =
2446fe6060f1SDimitry Andric       isEnabled(D, warn_unreachable) || isEnabled(D, warn_unreachable_break) ||
24470b57cec5SDimitry Andric       isEnabled(D, warn_unreachable_return) ||
24480b57cec5SDimitry Andric       isEnabled(D, warn_unreachable_loop_increment);
24490b57cec5SDimitry Andric 
2450fe6060f1SDimitry Andric   DefaultPolicy.enableThreadSafetyAnalysis = isEnabled(D, warn_double_lock);
24510b57cec5SDimitry Andric 
24520b57cec5SDimitry Andric   DefaultPolicy.enableConsumedAnalysis =
24530b57cec5SDimitry Andric       isEnabled(D, warn_use_in_invalid_state);
24540b57cec5SDimitry Andric }
24550b57cec5SDimitry Andric 
2456fe6060f1SDimitry Andric // We need this here for unique_ptr with forward declared class.
2457fe6060f1SDimitry Andric sema::AnalysisBasedWarnings::~AnalysisBasedWarnings() = default;
2458fe6060f1SDimitry Andric 
flushDiagnostics(Sema & S,const sema::FunctionScopeInfo * fscope)24590b57cec5SDimitry Andric static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope) {
24600b57cec5SDimitry Andric   for (const auto &D : fscope->PossiblyUnreachableDiags)
24610b57cec5SDimitry Andric     S.Diag(D.Loc, D.PD);
24620b57cec5SDimitry Andric }
24630b57cec5SDimitry Andric 
246406c3fb27SDimitry Andric // An AST Visitor that calls a callback function on each callable DEFINITION
246506c3fb27SDimitry Andric // that is NOT in a dependent context:
246606c3fb27SDimitry Andric class CallableVisitor : public RecursiveASTVisitor<CallableVisitor> {
246706c3fb27SDimitry Andric private:
246806c3fb27SDimitry Andric   llvm::function_ref<void(const Decl *)> Callback;
246906c3fb27SDimitry Andric 
247006c3fb27SDimitry Andric public:
CallableVisitor(llvm::function_ref<void (const Decl *)> Callback)247106c3fb27SDimitry Andric   CallableVisitor(llvm::function_ref<void(const Decl *)> Callback)
247206c3fb27SDimitry Andric       : Callback(Callback) {}
247306c3fb27SDimitry Andric 
VisitFunctionDecl(FunctionDecl * Node)247406c3fb27SDimitry Andric   bool VisitFunctionDecl(FunctionDecl *Node) {
247506c3fb27SDimitry Andric     if (cast<DeclContext>(Node)->isDependentContext())
247606c3fb27SDimitry Andric       return true; // Not to analyze dependent decl
247706c3fb27SDimitry Andric     // `FunctionDecl->hasBody()` returns true if the function has a body
247806c3fb27SDimitry Andric     // somewhere defined.  But we want to know if this `Node` has a body
247906c3fb27SDimitry Andric     // child.  So we use `doesThisDeclarationHaveABody`:
248006c3fb27SDimitry Andric     if (Node->doesThisDeclarationHaveABody())
248106c3fb27SDimitry Andric       Callback(Node);
248206c3fb27SDimitry Andric     return true;
248306c3fb27SDimitry Andric   }
248406c3fb27SDimitry Andric 
VisitBlockDecl(BlockDecl * Node)248506c3fb27SDimitry Andric   bool VisitBlockDecl(BlockDecl *Node) {
248606c3fb27SDimitry Andric     if (cast<DeclContext>(Node)->isDependentContext())
248706c3fb27SDimitry Andric       return true; // Not to analyze dependent decl
248806c3fb27SDimitry Andric     Callback(Node);
248906c3fb27SDimitry Andric     return true;
249006c3fb27SDimitry Andric   }
249106c3fb27SDimitry Andric 
VisitObjCMethodDecl(ObjCMethodDecl * Node)249206c3fb27SDimitry Andric   bool VisitObjCMethodDecl(ObjCMethodDecl *Node) {
249306c3fb27SDimitry Andric     if (cast<DeclContext>(Node)->isDependentContext())
249406c3fb27SDimitry Andric       return true; // Not to analyze dependent decl
249506c3fb27SDimitry Andric     if (Node->hasBody())
249606c3fb27SDimitry Andric       Callback(Node);
249706c3fb27SDimitry Andric     return true;
249806c3fb27SDimitry Andric   }
249906c3fb27SDimitry Andric 
VisitLambdaExpr(LambdaExpr * Node)250006c3fb27SDimitry Andric   bool VisitLambdaExpr(LambdaExpr *Node) {
250106c3fb27SDimitry Andric     return VisitFunctionDecl(Node->getCallOperator());
250206c3fb27SDimitry Andric   }
250306c3fb27SDimitry Andric 
shouldVisitTemplateInstantiations() const250406c3fb27SDimitry Andric   bool shouldVisitTemplateInstantiations() const { return true; }
shouldVisitImplicitCode() const250506c3fb27SDimitry Andric   bool shouldVisitImplicitCode() const { return false; }
250606c3fb27SDimitry Andric };
250706c3fb27SDimitry Andric 
IssueWarnings(TranslationUnitDecl * TU)250806c3fb27SDimitry Andric void clang::sema::AnalysisBasedWarnings::IssueWarnings(
250906c3fb27SDimitry Andric      TranslationUnitDecl *TU) {
251006c3fb27SDimitry Andric   if (!TU)
251106c3fb27SDimitry Andric     return; // This is unexpected, give up quietly.
251206c3fb27SDimitry Andric 
251306c3fb27SDimitry Andric   DiagnosticsEngine &Diags = S.getDiagnostics();
251406c3fb27SDimitry Andric 
251506c3fb27SDimitry Andric   if (S.hasUncompilableErrorOccurred() || Diags.getIgnoreAllWarnings())
251606c3fb27SDimitry Andric     // exit if having uncompilable errors or ignoring all warnings:
251706c3fb27SDimitry Andric     return;
251806c3fb27SDimitry Andric 
251906c3fb27SDimitry Andric   DiagnosticOptions &DiagOpts = Diags.getDiagnosticOptions();
252006c3fb27SDimitry Andric 
252106c3fb27SDimitry Andric   // UnsafeBufferUsage analysis settings.
252206c3fb27SDimitry Andric   bool UnsafeBufferUsageCanEmitSuggestions = S.getLangOpts().CPlusPlus20;
252306c3fb27SDimitry Andric   bool UnsafeBufferUsageShouldEmitSuggestions =  // Should != Can.
252406c3fb27SDimitry Andric       UnsafeBufferUsageCanEmitSuggestions &&
252506c3fb27SDimitry Andric       DiagOpts.ShowSafeBufferUsageSuggestions;
252606c3fb27SDimitry Andric   bool UnsafeBufferUsageShouldSuggestSuggestions =
252706c3fb27SDimitry Andric       UnsafeBufferUsageCanEmitSuggestions &&
252806c3fb27SDimitry Andric       !DiagOpts.ShowSafeBufferUsageSuggestions;
252906c3fb27SDimitry Andric   UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions);
253006c3fb27SDimitry Andric 
253106c3fb27SDimitry Andric   // The Callback function that performs analyses:
253206c3fb27SDimitry Andric   auto CallAnalyzers = [&](const Decl *Node) -> void {
253306c3fb27SDimitry Andric     // Perform unsafe buffer usage analysis:
253406c3fb27SDimitry Andric     if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation,
253506c3fb27SDimitry Andric                          Node->getBeginLoc()) ||
253606c3fb27SDimitry Andric         !Diags.isIgnored(diag::warn_unsafe_buffer_variable,
2537*0fca6ea1SDimitry Andric                          Node->getBeginLoc()) ||
2538*0fca6ea1SDimitry Andric         !Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container,
253906c3fb27SDimitry Andric                          Node->getBeginLoc())) {
254006c3fb27SDimitry Andric       clang::checkUnsafeBufferUsage(Node, R,
254106c3fb27SDimitry Andric                                     UnsafeBufferUsageShouldEmitSuggestions);
254206c3fb27SDimitry Andric     }
254306c3fb27SDimitry Andric 
254406c3fb27SDimitry Andric     // More analysis ...
254506c3fb27SDimitry Andric   };
254606c3fb27SDimitry Andric   // Emit per-function analysis-based warnings that require the whole-TU
254706c3fb27SDimitry Andric   // reasoning. Check if any of them is enabled at all before scanning the AST:
254806c3fb27SDimitry Andric   if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, SourceLocation()) ||
2549*0fca6ea1SDimitry Andric       !Diags.isIgnored(diag::warn_unsafe_buffer_variable, SourceLocation()) ||
2550*0fca6ea1SDimitry Andric       !Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2551*0fca6ea1SDimitry Andric                        SourceLocation())) {
255206c3fb27SDimitry Andric     CallableVisitor(CallAnalyzers).TraverseTranslationUnitDecl(TU);
255306c3fb27SDimitry Andric   }
255406c3fb27SDimitry Andric }
255506c3fb27SDimitry Andric 
IssueWarnings(sema::AnalysisBasedWarnings::Policy P,sema::FunctionScopeInfo * fscope,const Decl * D,QualType BlockType)2556fe6060f1SDimitry Andric void clang::sema::AnalysisBasedWarnings::IssueWarnings(
2557fe6060f1SDimitry Andric     sema::AnalysisBasedWarnings::Policy P, sema::FunctionScopeInfo *fscope,
25580b57cec5SDimitry Andric     const Decl *D, QualType BlockType) {
25590b57cec5SDimitry Andric 
25600b57cec5SDimitry Andric   // We avoid doing analysis-based warnings when there are errors for
25610b57cec5SDimitry Andric   // two reasons:
25620b57cec5SDimitry Andric   // (1) The CFGs often can't be constructed (if the body is invalid), so
25630b57cec5SDimitry Andric   //     don't bother trying.
25640b57cec5SDimitry Andric   // (2) The code already has problems; running the analysis just takes more
25650b57cec5SDimitry Andric   //     time.
25660b57cec5SDimitry Andric   DiagnosticsEngine &Diags = S.getDiagnostics();
25670b57cec5SDimitry Andric 
25680b57cec5SDimitry Andric   // Do not do any analysis if we are going to just ignore them.
25690b57cec5SDimitry Andric   if (Diags.getIgnoreAllWarnings() ||
25700b57cec5SDimitry Andric       (Diags.getSuppressSystemWarnings() &&
25710b57cec5SDimitry Andric        S.SourceMgr.isInSystemHeader(D->getLocation())))
25720b57cec5SDimitry Andric     return;
25730b57cec5SDimitry Andric 
25740b57cec5SDimitry Andric   // For code in dependent contexts, we'll do this at instantiation time.
25750b57cec5SDimitry Andric   if (cast<DeclContext>(D)->isDependentContext())
25760b57cec5SDimitry Andric     return;
25770b57cec5SDimitry Andric 
2578e8d8bef9SDimitry Andric   if (S.hasUncompilableErrorOccurred()) {
25790b57cec5SDimitry Andric     // Flush out any possibly unreachable diagnostics.
25800b57cec5SDimitry Andric     flushDiagnostics(S, fscope);
25810b57cec5SDimitry Andric     return;
25820b57cec5SDimitry Andric   }
25830b57cec5SDimitry Andric 
25840b57cec5SDimitry Andric   const Stmt *Body = D->getBody();
25850b57cec5SDimitry Andric   assert(Body);
25860b57cec5SDimitry Andric 
25870b57cec5SDimitry Andric   // Construct the analysis context with the specified CFG build options.
25880b57cec5SDimitry Andric   AnalysisDeclContext AC(/* AnalysisDeclContextManager */ nullptr, D);
25890b57cec5SDimitry Andric 
25900b57cec5SDimitry Andric   // Don't generate EH edges for CallExprs as we'd like to avoid the n^2
25910b57cec5SDimitry Andric   // explosion for destructors that can result and the compile time hit.
25920b57cec5SDimitry Andric   AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true;
25930b57cec5SDimitry Andric   AC.getCFGBuildOptions().AddEHEdges = false;
25940b57cec5SDimitry Andric   AC.getCFGBuildOptions().AddInitializers = true;
25950b57cec5SDimitry Andric   AC.getCFGBuildOptions().AddImplicitDtors = true;
25960b57cec5SDimitry Andric   AC.getCFGBuildOptions().AddTemporaryDtors = true;
25970b57cec5SDimitry Andric   AC.getCFGBuildOptions().AddCXXNewAllocator = false;
25980b57cec5SDimitry Andric   AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true;
25990b57cec5SDimitry Andric 
26000b57cec5SDimitry Andric   // Force that certain expressions appear as CFGElements in the CFG.  This
26010b57cec5SDimitry Andric   // is used to speed up various analyses.
26020b57cec5SDimitry Andric   // FIXME: This isn't the right factoring.  This is here for initial
26030b57cec5SDimitry Andric   // prototyping, but we need a way for analyses to say what expressions they
26040b57cec5SDimitry Andric   // expect to always be CFGElements and then fill in the BuildOptions
26050b57cec5SDimitry Andric   // appropriately.  This is essentially a layering violation.
26060b57cec5SDimitry Andric   if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||
26070b57cec5SDimitry Andric       P.enableConsumedAnalysis) {
26080b57cec5SDimitry Andric     // Unreachable code analysis and thread safety require a linearized CFG.
26090b57cec5SDimitry Andric     AC.getCFGBuildOptions().setAllAlwaysAdd();
26100b57cec5SDimitry Andric   }
26110b57cec5SDimitry Andric   else {
26120b57cec5SDimitry Andric     AC.getCFGBuildOptions()
26130b57cec5SDimitry Andric       .setAlwaysAdd(Stmt::BinaryOperatorClass)
26140b57cec5SDimitry Andric       .setAlwaysAdd(Stmt::CompoundAssignOperatorClass)
26150b57cec5SDimitry Andric       .setAlwaysAdd(Stmt::BlockExprClass)
26160b57cec5SDimitry Andric       .setAlwaysAdd(Stmt::CStyleCastExprClass)
26170b57cec5SDimitry Andric       .setAlwaysAdd(Stmt::DeclRefExprClass)
26180b57cec5SDimitry Andric       .setAlwaysAdd(Stmt::ImplicitCastExprClass)
2619349cc55cSDimitry Andric       .setAlwaysAdd(Stmt::UnaryOperatorClass);
26200b57cec5SDimitry Andric   }
26210b57cec5SDimitry Andric 
2622a7dea167SDimitry Andric   // Install the logical handler.
2623bdd1243dSDimitry Andric   std::optional<LogicalErrorHandler> LEH;
2624a7dea167SDimitry Andric   if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
26250b57cec5SDimitry Andric     LEH.emplace(S);
26260b57cec5SDimitry Andric     AC.getCFGBuildOptions().Observer = &*LEH;
26270b57cec5SDimitry Andric   }
26280b57cec5SDimitry Andric 
26290b57cec5SDimitry Andric   // Emit delayed diagnostics.
26300b57cec5SDimitry Andric   if (!fscope->PossiblyUnreachableDiags.empty()) {
26310b57cec5SDimitry Andric     bool analyzed = false;
26320b57cec5SDimitry Andric 
26330b57cec5SDimitry Andric     // Register the expressions with the CFGBuilder.
26340b57cec5SDimitry Andric     for (const auto &D : fscope->PossiblyUnreachableDiags) {
26350b57cec5SDimitry Andric       for (const Stmt *S : D.Stmts)
26360b57cec5SDimitry Andric         AC.registerForcedBlockExpression(S);
26370b57cec5SDimitry Andric     }
26380b57cec5SDimitry Andric 
26390b57cec5SDimitry Andric     if (AC.getCFG()) {
26400b57cec5SDimitry Andric       analyzed = true;
26410b57cec5SDimitry Andric       for (const auto &D : fscope->PossiblyUnreachableDiags) {
26420b57cec5SDimitry Andric         bool AllReachable = true;
26430b57cec5SDimitry Andric         for (const Stmt *S : D.Stmts) {
26440b57cec5SDimitry Andric           const CFGBlock *block = AC.getBlockForRegisteredExpression(S);
26450b57cec5SDimitry Andric           CFGReverseBlockReachabilityAnalysis *cra =
26460b57cec5SDimitry Andric               AC.getCFGReachablityAnalysis();
26470b57cec5SDimitry Andric           // FIXME: We should be able to assert that block is non-null, but
26480b57cec5SDimitry Andric           // the CFG analysis can skip potentially-evaluated expressions in
26490b57cec5SDimitry Andric           // edge cases; see test/Sema/vla-2.c.
26500b57cec5SDimitry Andric           if (block && cra) {
26510b57cec5SDimitry Andric             // Can this block be reached from the entrance?
26520b57cec5SDimitry Andric             if (!cra->isReachable(&AC.getCFG()->getEntry(), block)) {
26530b57cec5SDimitry Andric               AllReachable = false;
26540b57cec5SDimitry Andric               break;
26550b57cec5SDimitry Andric             }
26560b57cec5SDimitry Andric           }
26570b57cec5SDimitry Andric           // If we cannot map to a basic block, assume the statement is
26580b57cec5SDimitry Andric           // reachable.
26590b57cec5SDimitry Andric         }
26600b57cec5SDimitry Andric 
26610b57cec5SDimitry Andric         if (AllReachable)
26620b57cec5SDimitry Andric           S.Diag(D.Loc, D.PD);
26630b57cec5SDimitry Andric       }
26640b57cec5SDimitry Andric     }
26650b57cec5SDimitry Andric 
26660b57cec5SDimitry Andric     if (!analyzed)
26670b57cec5SDimitry Andric       flushDiagnostics(S, fscope);
26680b57cec5SDimitry Andric   }
26690b57cec5SDimitry Andric 
26700b57cec5SDimitry Andric   // Warning: check missing 'return'
26710b57cec5SDimitry Andric   if (P.enableCheckFallThrough) {
26720b57cec5SDimitry Andric     const CheckFallThroughDiagnostics &CD =
26730b57cec5SDimitry Andric         (isa<BlockDecl>(D)
26740b57cec5SDimitry Andric              ? CheckFallThroughDiagnostics::MakeForBlock()
26750b57cec5SDimitry Andric              : (isa<CXXMethodDecl>(D) &&
26760b57cec5SDimitry Andric                 cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call &&
26770b57cec5SDimitry Andric                 cast<CXXMethodDecl>(D)->getParent()->isLambda())
26780b57cec5SDimitry Andric                    ? CheckFallThroughDiagnostics::MakeForLambda()
26790b57cec5SDimitry Andric                    : (fscope->isCoroutine()
26800b57cec5SDimitry Andric                           ? CheckFallThroughDiagnostics::MakeForCoroutine(D)
26810b57cec5SDimitry Andric                           : CheckFallThroughDiagnostics::MakeForFunction(D)));
26820b57cec5SDimitry Andric     CheckFallThroughForBody(S, D, Body, BlockType, CD, AC, fscope);
26830b57cec5SDimitry Andric   }
26840b57cec5SDimitry Andric 
26850b57cec5SDimitry Andric   // Warning: check for unreachable code
26860b57cec5SDimitry Andric   if (P.enableCheckUnreachable) {
26870b57cec5SDimitry Andric     // Only check for unreachable code on non-template instantiations.
26880b57cec5SDimitry Andric     // Different template instantiations can effectively change the control-flow
26890b57cec5SDimitry Andric     // and it is very difficult to prove that a snippet of code in a template
26900b57cec5SDimitry Andric     // is unreachable for all instantiations.
26910b57cec5SDimitry Andric     bool isTemplateInstantiation = false;
26920b57cec5SDimitry Andric     if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
26930b57cec5SDimitry Andric       isTemplateInstantiation = Function->isTemplateInstantiation();
26940b57cec5SDimitry Andric     if (!isTemplateInstantiation)
26950b57cec5SDimitry Andric       CheckUnreachable(S, AC);
26960b57cec5SDimitry Andric   }
26970b57cec5SDimitry Andric 
26980b57cec5SDimitry Andric   // Check for thread safety violations
26990b57cec5SDimitry Andric   if (P.enableThreadSafetyAnalysis) {
27000b57cec5SDimitry Andric     SourceLocation FL = AC.getDecl()->getLocation();
27010b57cec5SDimitry Andric     SourceLocation FEL = AC.getDecl()->getEndLoc();
27020b57cec5SDimitry Andric     threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
27030b57cec5SDimitry Andric     if (!Diags.isIgnored(diag::warn_thread_safety_beta, D->getBeginLoc()))
27040b57cec5SDimitry Andric       Reporter.setIssueBetaWarnings(true);
27050b57cec5SDimitry Andric     if (!Diags.isIgnored(diag::warn_thread_safety_verbose, D->getBeginLoc()))
27060b57cec5SDimitry Andric       Reporter.setVerbose(true);
27070b57cec5SDimitry Andric 
27080b57cec5SDimitry Andric     threadSafety::runThreadSafetyAnalysis(AC, Reporter,
27090b57cec5SDimitry Andric                                           &S.ThreadSafetyDeclCache);
27100b57cec5SDimitry Andric     Reporter.emitDiagnostics();
27110b57cec5SDimitry Andric   }
27120b57cec5SDimitry Andric 
27130b57cec5SDimitry Andric   // Check for violations of consumed properties.
27140b57cec5SDimitry Andric   if (P.enableConsumedAnalysis) {
27150b57cec5SDimitry Andric     consumed::ConsumedWarningsHandler WarningHandler(S);
27160b57cec5SDimitry Andric     consumed::ConsumedAnalyzer Analyzer(WarningHandler);
27170b57cec5SDimitry Andric     Analyzer.run(AC);
27180b57cec5SDimitry Andric   }
27190b57cec5SDimitry Andric 
27200b57cec5SDimitry Andric   if (!Diags.isIgnored(diag::warn_uninit_var, D->getBeginLoc()) ||
27210b57cec5SDimitry Andric       !Diags.isIgnored(diag::warn_sometimes_uninit_var, D->getBeginLoc()) ||
27225ffd83dbSDimitry Andric       !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getBeginLoc()) ||
27235ffd83dbSDimitry Andric       !Diags.isIgnored(diag::warn_uninit_const_reference, D->getBeginLoc())) {
27240b57cec5SDimitry Andric     if (CFG *cfg = AC.getCFG()) {
27250b57cec5SDimitry Andric       UninitValsDiagReporter reporter(S);
27260b57cec5SDimitry Andric       UninitVariablesAnalysisStats stats;
27270b57cec5SDimitry Andric       std::memset(&stats, 0, sizeof(UninitVariablesAnalysisStats));
27280b57cec5SDimitry Andric       runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC,
27290b57cec5SDimitry Andric                                         reporter, stats);
27300b57cec5SDimitry Andric 
27310b57cec5SDimitry Andric       if (S.CollectStats && stats.NumVariablesAnalyzed > 0) {
27320b57cec5SDimitry Andric         ++NumUninitAnalysisFunctions;
27330b57cec5SDimitry Andric         NumUninitAnalysisVariables += stats.NumVariablesAnalyzed;
27340b57cec5SDimitry Andric         NumUninitAnalysisBlockVisits += stats.NumBlockVisits;
27350b57cec5SDimitry Andric         MaxUninitAnalysisVariablesPerFunction =
27360b57cec5SDimitry Andric             std::max(MaxUninitAnalysisVariablesPerFunction,
27370b57cec5SDimitry Andric                      stats.NumVariablesAnalyzed);
27380b57cec5SDimitry Andric         MaxUninitAnalysisBlockVisitsPerFunction =
27390b57cec5SDimitry Andric             std::max(MaxUninitAnalysisBlockVisitsPerFunction,
27400b57cec5SDimitry Andric                      stats.NumBlockVisits);
27410b57cec5SDimitry Andric       }
27420b57cec5SDimitry Andric     }
27430b57cec5SDimitry Andric   }
27440b57cec5SDimitry Andric 
2745e8d8bef9SDimitry Andric   // Check for violations of "called once" parameter properties.
2746fe6060f1SDimitry Andric   if (S.getLangOpts().ObjC && !S.getLangOpts().CPlusPlus &&
2747e8d8bef9SDimitry Andric       shouldAnalyzeCalledOnceParameters(Diags, D->getBeginLoc())) {
2748e8d8bef9SDimitry Andric     if (AC.getCFG()) {
2749fe6060f1SDimitry Andric       CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);
2750e8d8bef9SDimitry Andric       checkCalledOnceParameters(
2751e8d8bef9SDimitry Andric           AC, Reporter,
2752e8d8bef9SDimitry Andric           shouldAnalyzeCalledOnceConventions(Diags, D->getBeginLoc()));
2753e8d8bef9SDimitry Andric     }
2754e8d8bef9SDimitry Andric   }
2755e8d8bef9SDimitry Andric 
27560b57cec5SDimitry Andric   bool FallThroughDiagFull =
27570b57cec5SDimitry Andric       !Diags.isIgnored(diag::warn_unannotated_fallthrough, D->getBeginLoc());
27580b57cec5SDimitry Andric   bool FallThroughDiagPerFunction = !Diags.isIgnored(
27590b57cec5SDimitry Andric       diag::warn_unannotated_fallthrough_per_function, D->getBeginLoc());
27600b57cec5SDimitry Andric   if (FallThroughDiagFull || FallThroughDiagPerFunction ||
27610b57cec5SDimitry Andric       fscope->HasFallthroughStmt) {
27620b57cec5SDimitry Andric     DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull);
27630b57cec5SDimitry Andric   }
27640b57cec5SDimitry Andric 
27650b57cec5SDimitry Andric   if (S.getLangOpts().ObjCWeak &&
27660b57cec5SDimitry Andric       !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, D->getBeginLoc()))
27670b57cec5SDimitry Andric     diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap());
27680b57cec5SDimitry Andric 
27690b57cec5SDimitry Andric 
27700b57cec5SDimitry Andric   // Check for infinite self-recursion in functions
27710b57cec5SDimitry Andric   if (!Diags.isIgnored(diag::warn_infinite_recursive_function,
27720b57cec5SDimitry Andric                        D->getBeginLoc())) {
27730b57cec5SDimitry Andric     if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
27740b57cec5SDimitry Andric       checkRecursiveFunction(S, FD, Body, AC);
27750b57cec5SDimitry Andric     }
27760b57cec5SDimitry Andric   }
27770b57cec5SDimitry Andric 
27780b57cec5SDimitry Andric   // Check for throw out of non-throwing function.
27790b57cec5SDimitry Andric   if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getBeginLoc()))
27800b57cec5SDimitry Andric     if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
278106c3fb27SDimitry Andric       if (S.getLangOpts().CPlusPlus && !fscope->isCoroutine() && isNoexcept(FD))
27820b57cec5SDimitry Andric         checkThrowInNonThrowingFunc(S, FD, AC);
27830b57cec5SDimitry Andric 
27840b57cec5SDimitry Andric   // If none of the previous checks caused a CFG build, trigger one here
2785a7dea167SDimitry Andric   // for the logical error handler.
2786a7dea167SDimitry Andric   if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
27870b57cec5SDimitry Andric     AC.getCFG();
27880b57cec5SDimitry Andric   }
27890b57cec5SDimitry Andric 
27900b57cec5SDimitry Andric   // Collect statistics about the CFG if it was built.
27910b57cec5SDimitry Andric   if (S.CollectStats && AC.isCFGBuilt()) {
27920b57cec5SDimitry Andric     ++NumFunctionsAnalyzed;
27930b57cec5SDimitry Andric     if (CFG *cfg = AC.getCFG()) {
27940b57cec5SDimitry Andric       // If we successfully built a CFG for this context, record some more
27950b57cec5SDimitry Andric       // detail information about it.
27960b57cec5SDimitry Andric       NumCFGBlocks += cfg->getNumBlockIDs();
27970b57cec5SDimitry Andric       MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
27980b57cec5SDimitry Andric                                          cfg->getNumBlockIDs());
27990b57cec5SDimitry Andric     } else {
28000b57cec5SDimitry Andric       ++NumFunctionsWithBadCFGs;
28010b57cec5SDimitry Andric     }
28020b57cec5SDimitry Andric   }
28030b57cec5SDimitry Andric }
28040b57cec5SDimitry Andric 
PrintStats() const28050b57cec5SDimitry Andric void clang::sema::AnalysisBasedWarnings::PrintStats() const {
28060b57cec5SDimitry Andric   llvm::errs() << "\n*** Analysis Based Warnings Stats:\n";
28070b57cec5SDimitry Andric 
28080b57cec5SDimitry Andric   unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
28090b57cec5SDimitry Andric   unsigned AvgCFGBlocksPerFunction =
28100b57cec5SDimitry Andric       !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
28110b57cec5SDimitry Andric   llvm::errs() << NumFunctionsAnalyzed << " functions analyzed ("
28120b57cec5SDimitry Andric                << NumFunctionsWithBadCFGs << " w/o CFGs).\n"
28130b57cec5SDimitry Andric                << "  " << NumCFGBlocks << " CFG blocks built.\n"
28140b57cec5SDimitry Andric                << "  " << AvgCFGBlocksPerFunction
28150b57cec5SDimitry Andric                << " average CFG blocks per function.\n"
28160b57cec5SDimitry Andric                << "  " << MaxCFGBlocksPerFunction
28170b57cec5SDimitry Andric                << " max CFG blocks per function.\n";
28180b57cec5SDimitry Andric 
28190b57cec5SDimitry Andric   unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
28200b57cec5SDimitry Andric       : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
28210b57cec5SDimitry Andric   unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
28220b57cec5SDimitry Andric       : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
28230b57cec5SDimitry Andric   llvm::errs() << NumUninitAnalysisFunctions
28240b57cec5SDimitry Andric                << " functions analyzed for uninitialiazed variables\n"
28250b57cec5SDimitry Andric                << "  " << NumUninitAnalysisVariables << " variables analyzed.\n"
28260b57cec5SDimitry Andric                << "  " << AvgUninitVariablesPerFunction
28270b57cec5SDimitry Andric                << " average variables per function.\n"
28280b57cec5SDimitry Andric                << "  " << MaxUninitAnalysisVariablesPerFunction
28290b57cec5SDimitry Andric                << " max variables per function.\n"
28300b57cec5SDimitry Andric                << "  " << NumUninitAnalysisBlockVisits << " block visits.\n"
28310b57cec5SDimitry Andric                << "  " << AvgUninitBlockVisitsPerFunction
28320b57cec5SDimitry Andric                << " average block visits per function.\n"
28330b57cec5SDimitry Andric                << "  " << MaxUninitAnalysisBlockVisitsPerFunction
28340b57cec5SDimitry Andric                << " max block visits per function.\n";
28350b57cec5SDimitry Andric }
2836