xref: /openbsd-src/gnu/llvm/clang/lib/Sema/AnalysisBasedWarnings.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- C++ -*-=//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file defines analysis_warnings::[Policy,Executor].
10e5dd7070Spatrick // Together they are used by Sema to issue warnings based on inexpensive
11e5dd7070Spatrick // static analysis algorithms in libAnalysis.
12e5dd7070Spatrick //
13e5dd7070Spatrick //===----------------------------------------------------------------------===//
14e5dd7070Spatrick 
15e5dd7070Spatrick #include "clang/Sema/AnalysisBasedWarnings.h"
16e5dd7070Spatrick #include "clang/AST/DeclCXX.h"
17e5dd7070Spatrick #include "clang/AST/DeclObjC.h"
18e5dd7070Spatrick #include "clang/AST/EvaluatedExprVisitor.h"
19*12c85518Srobert #include "clang/AST/Expr.h"
20e5dd7070Spatrick #include "clang/AST/ExprCXX.h"
21e5dd7070Spatrick #include "clang/AST/ExprObjC.h"
22*12c85518Srobert #include "clang/AST/OperationKinds.h"
23e5dd7070Spatrick #include "clang/AST/ParentMap.h"
24e5dd7070Spatrick #include "clang/AST/RecursiveASTVisitor.h"
25e5dd7070Spatrick #include "clang/AST/StmtCXX.h"
26e5dd7070Spatrick #include "clang/AST/StmtObjC.h"
27e5dd7070Spatrick #include "clang/AST/StmtVisitor.h"
28e5dd7070Spatrick #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
29a9ac8606Spatrick #include "clang/Analysis/Analyses/CalledOnceCheck.h"
30e5dd7070Spatrick #include "clang/Analysis/Analyses/Consumed.h"
31e5dd7070Spatrick #include "clang/Analysis/Analyses/ReachableCode.h"
32e5dd7070Spatrick #include "clang/Analysis/Analyses/ThreadSafety.h"
33e5dd7070Spatrick #include "clang/Analysis/Analyses/UninitializedValues.h"
34*12c85518Srobert #include "clang/Analysis/Analyses/UnsafeBufferUsage.h"
35e5dd7070Spatrick #include "clang/Analysis/AnalysisDeclContext.h"
36e5dd7070Spatrick #include "clang/Analysis/CFG.h"
37e5dd7070Spatrick #include "clang/Analysis/CFGStmtMap.h"
38e5dd7070Spatrick #include "clang/Basic/SourceLocation.h"
39e5dd7070Spatrick #include "clang/Basic/SourceManager.h"
40e5dd7070Spatrick #include "clang/Lex/Preprocessor.h"
41e5dd7070Spatrick #include "clang/Sema/ScopeInfo.h"
42e5dd7070Spatrick #include "clang/Sema/SemaInternal.h"
43a9ac8606Spatrick #include "llvm/ADT/ArrayRef.h"
44e5dd7070Spatrick #include "llvm/ADT/BitVector.h"
45e5dd7070Spatrick #include "llvm/ADT/MapVector.h"
46e5dd7070Spatrick #include "llvm/ADT/SmallString.h"
47e5dd7070Spatrick #include "llvm/ADT/SmallVector.h"
48e5dd7070Spatrick #include "llvm/ADT/StringRef.h"
49e5dd7070Spatrick #include "llvm/Support/Casting.h"
50e5dd7070Spatrick #include <algorithm>
51e5dd7070Spatrick #include <deque>
52e5dd7070Spatrick #include <iterator>
53*12c85518Srobert #include <optional>
54e5dd7070Spatrick 
55e5dd7070Spatrick using namespace clang;
56e5dd7070Spatrick 
57e5dd7070Spatrick //===----------------------------------------------------------------------===//
58e5dd7070Spatrick // Unreachable code analysis.
59e5dd7070Spatrick //===----------------------------------------------------------------------===//
60e5dd7070Spatrick 
61e5dd7070Spatrick namespace {
62e5dd7070Spatrick   class UnreachableCodeHandler : public reachable_code::Callback {
63e5dd7070Spatrick     Sema &S;
64e5dd7070Spatrick     SourceRange PreviousSilenceableCondVal;
65e5dd7070Spatrick 
66e5dd7070Spatrick   public:
UnreachableCodeHandler(Sema & s)67e5dd7070Spatrick     UnreachableCodeHandler(Sema &s) : S(s) {}
68e5dd7070Spatrick 
HandleUnreachable(reachable_code::UnreachableKind UK,SourceLocation L,SourceRange SilenceableCondVal,SourceRange R1,SourceRange R2)69e5dd7070Spatrick     void HandleUnreachable(reachable_code::UnreachableKind UK,
70e5dd7070Spatrick                            SourceLocation L,
71e5dd7070Spatrick                            SourceRange SilenceableCondVal,
72e5dd7070Spatrick                            SourceRange R1,
73e5dd7070Spatrick                            SourceRange R2) override {
74e5dd7070Spatrick       // Avoid reporting multiple unreachable code diagnostics that are
75e5dd7070Spatrick       // triggered by the same conditional value.
76e5dd7070Spatrick       if (PreviousSilenceableCondVal.isValid() &&
77e5dd7070Spatrick           SilenceableCondVal.isValid() &&
78e5dd7070Spatrick           PreviousSilenceableCondVal == SilenceableCondVal)
79e5dd7070Spatrick         return;
80e5dd7070Spatrick       PreviousSilenceableCondVal = SilenceableCondVal;
81e5dd7070Spatrick 
82e5dd7070Spatrick       unsigned diag = diag::warn_unreachable;
83e5dd7070Spatrick       switch (UK) {
84e5dd7070Spatrick         case reachable_code::UK_Break:
85e5dd7070Spatrick           diag = diag::warn_unreachable_break;
86e5dd7070Spatrick           break;
87e5dd7070Spatrick         case reachable_code::UK_Return:
88e5dd7070Spatrick           diag = diag::warn_unreachable_return;
89e5dd7070Spatrick           break;
90e5dd7070Spatrick         case reachable_code::UK_Loop_Increment:
91e5dd7070Spatrick           diag = diag::warn_unreachable_loop_increment;
92e5dd7070Spatrick           break;
93e5dd7070Spatrick         case reachable_code::UK_Other:
94e5dd7070Spatrick           break;
95e5dd7070Spatrick       }
96e5dd7070Spatrick 
97e5dd7070Spatrick       S.Diag(L, diag) << R1 << R2;
98e5dd7070Spatrick 
99e5dd7070Spatrick       SourceLocation Open = SilenceableCondVal.getBegin();
100e5dd7070Spatrick       if (Open.isValid()) {
101e5dd7070Spatrick         SourceLocation Close = SilenceableCondVal.getEnd();
102e5dd7070Spatrick         Close = S.getLocForEndOfToken(Close);
103e5dd7070Spatrick         if (Close.isValid()) {
104e5dd7070Spatrick           S.Diag(Open, diag::note_unreachable_silence)
105e5dd7070Spatrick             << FixItHint::CreateInsertion(Open, "/* DISABLES CODE */ (")
106e5dd7070Spatrick             << FixItHint::CreateInsertion(Close, ")");
107e5dd7070Spatrick         }
108e5dd7070Spatrick       }
109e5dd7070Spatrick     }
110e5dd7070Spatrick   };
111e5dd7070Spatrick } // anonymous namespace
112e5dd7070Spatrick 
113e5dd7070Spatrick /// CheckUnreachable - Check for unreachable code.
CheckUnreachable(Sema & S,AnalysisDeclContext & AC)114e5dd7070Spatrick static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC) {
115e5dd7070Spatrick   // As a heuristic prune all diagnostics not in the main file.  Currently
116e5dd7070Spatrick   // the majority of warnings in headers are false positives.  These
117e5dd7070Spatrick   // are largely caused by configuration state, e.g. preprocessor
118e5dd7070Spatrick   // defined code, etc.
119e5dd7070Spatrick   //
120e5dd7070Spatrick   // Note that this is also a performance optimization.  Analyzing
121e5dd7070Spatrick   // headers many times can be expensive.
122e5dd7070Spatrick   if (!S.getSourceManager().isInMainFile(AC.getDecl()->getBeginLoc()))
123e5dd7070Spatrick     return;
124e5dd7070Spatrick 
125e5dd7070Spatrick   UnreachableCodeHandler UC(S);
126e5dd7070Spatrick   reachable_code::FindUnreachableCode(AC, S.getPreprocessor(), UC);
127e5dd7070Spatrick }
128e5dd7070Spatrick 
129e5dd7070Spatrick namespace {
130e5dd7070Spatrick /// Warn on logical operator errors in CFGBuilder
131e5dd7070Spatrick class LogicalErrorHandler : public CFGCallback {
132e5dd7070Spatrick   Sema &S;
133e5dd7070Spatrick 
134e5dd7070Spatrick public:
LogicalErrorHandler(Sema & S)135*12c85518Srobert   LogicalErrorHandler(Sema &S) : S(S) {}
136e5dd7070Spatrick 
HasMacroID(const Expr * E)137e5dd7070Spatrick   static bool HasMacroID(const Expr *E) {
138e5dd7070Spatrick     if (E->getExprLoc().isMacroID())
139e5dd7070Spatrick       return true;
140e5dd7070Spatrick 
141e5dd7070Spatrick     // Recurse to children.
142e5dd7070Spatrick     for (const Stmt *SubStmt : E->children())
143e5dd7070Spatrick       if (const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt))
144e5dd7070Spatrick         if (HasMacroID(SubExpr))
145e5dd7070Spatrick           return true;
146e5dd7070Spatrick 
147e5dd7070Spatrick     return false;
148e5dd7070Spatrick   }
149e5dd7070Spatrick 
compareAlwaysTrue(const BinaryOperator * B,bool isAlwaysTrue)150e5dd7070Spatrick   void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) override {
151e5dd7070Spatrick     if (HasMacroID(B))
152e5dd7070Spatrick       return;
153e5dd7070Spatrick 
154e5dd7070Spatrick     SourceRange DiagRange = B->getSourceRange();
155e5dd7070Spatrick     S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison)
156e5dd7070Spatrick         << DiagRange << isAlwaysTrue;
157e5dd7070Spatrick   }
158e5dd7070Spatrick 
compareBitwiseEquality(const BinaryOperator * B,bool isAlwaysTrue)159e5dd7070Spatrick   void compareBitwiseEquality(const BinaryOperator *B,
160e5dd7070Spatrick                               bool isAlwaysTrue) override {
161e5dd7070Spatrick     if (HasMacroID(B))
162e5dd7070Spatrick       return;
163e5dd7070Spatrick 
164e5dd7070Spatrick     SourceRange DiagRange = B->getSourceRange();
165e5dd7070Spatrick     S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_always)
166e5dd7070Spatrick         << DiagRange << isAlwaysTrue;
167e5dd7070Spatrick   }
168e5dd7070Spatrick 
compareBitwiseOr(const BinaryOperator * B)169e5dd7070Spatrick   void compareBitwiseOr(const BinaryOperator *B) override {
170e5dd7070Spatrick     if (HasMacroID(B))
171e5dd7070Spatrick       return;
172e5dd7070Spatrick 
173e5dd7070Spatrick     SourceRange DiagRange = B->getSourceRange();
174e5dd7070Spatrick     S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;
175e5dd7070Spatrick   }
176e5dd7070Spatrick 
hasActiveDiagnostics(DiagnosticsEngine & Diags,SourceLocation Loc)177e5dd7070Spatrick   static bool hasActiveDiagnostics(DiagnosticsEngine &Diags,
178e5dd7070Spatrick                                    SourceLocation Loc) {
179e5dd7070Spatrick     return !Diags.isIgnored(diag::warn_tautological_overlap_comparison, Loc) ||
180e5dd7070Spatrick            !Diags.isIgnored(diag::warn_comparison_bitwise_or, Loc);
181e5dd7070Spatrick   }
182e5dd7070Spatrick };
183e5dd7070Spatrick } // anonymous namespace
184e5dd7070Spatrick 
185e5dd7070Spatrick //===----------------------------------------------------------------------===//
186e5dd7070Spatrick // Check for infinite self-recursion in functions
187e5dd7070Spatrick //===----------------------------------------------------------------------===//
188e5dd7070Spatrick 
189e5dd7070Spatrick // Returns true if the function is called anywhere within the CFGBlock.
190e5dd7070Spatrick // For member functions, the additional condition of being call from the
191e5dd7070Spatrick // this pointer is required.
hasRecursiveCallInPath(const FunctionDecl * FD,CFGBlock & Block)192e5dd7070Spatrick static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block) {
193e5dd7070Spatrick   // Process all the Stmt's in this block to find any calls to FD.
194e5dd7070Spatrick   for (const auto &B : Block) {
195e5dd7070Spatrick     if (B.getKind() != CFGElement::Statement)
196e5dd7070Spatrick       continue;
197e5dd7070Spatrick 
198e5dd7070Spatrick     const CallExpr *CE = dyn_cast<CallExpr>(B.getAs<CFGStmt>()->getStmt());
199e5dd7070Spatrick     if (!CE || !CE->getCalleeDecl() ||
200e5dd7070Spatrick         CE->getCalleeDecl()->getCanonicalDecl() != FD)
201e5dd7070Spatrick       continue;
202e5dd7070Spatrick 
203e5dd7070Spatrick     // Skip function calls which are qualified with a templated class.
204e5dd7070Spatrick     if (const DeclRefExpr *DRE =
205e5dd7070Spatrick             dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenImpCasts())) {
206e5dd7070Spatrick       if (NestedNameSpecifier *NNS = DRE->getQualifier()) {
207e5dd7070Spatrick         if (NNS->getKind() == NestedNameSpecifier::TypeSpec &&
208e5dd7070Spatrick             isa<TemplateSpecializationType>(NNS->getAsType())) {
209e5dd7070Spatrick           continue;
210e5dd7070Spatrick         }
211e5dd7070Spatrick       }
212e5dd7070Spatrick     }
213e5dd7070Spatrick 
214e5dd7070Spatrick     const CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(CE);
215e5dd7070Spatrick     if (!MCE || isa<CXXThisExpr>(MCE->getImplicitObjectArgument()) ||
216e5dd7070Spatrick         !MCE->getMethodDecl()->isVirtual())
217e5dd7070Spatrick       return true;
218e5dd7070Spatrick   }
219e5dd7070Spatrick   return false;
220e5dd7070Spatrick }
221e5dd7070Spatrick 
222e5dd7070Spatrick // Returns true if every path from the entry block passes through a call to FD.
checkForRecursiveFunctionCall(const FunctionDecl * FD,CFG * cfg)223e5dd7070Spatrick static bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg) {
224e5dd7070Spatrick   llvm::SmallPtrSet<CFGBlock *, 16> Visited;
225e5dd7070Spatrick   llvm::SmallVector<CFGBlock *, 16> WorkList;
226e5dd7070Spatrick   // Keep track of whether we found at least one recursive path.
227e5dd7070Spatrick   bool foundRecursion = false;
228e5dd7070Spatrick 
229e5dd7070Spatrick   const unsigned ExitID = cfg->getExit().getBlockID();
230e5dd7070Spatrick 
231e5dd7070Spatrick   // Seed the work list with the entry block.
232e5dd7070Spatrick   WorkList.push_back(&cfg->getEntry());
233e5dd7070Spatrick 
234e5dd7070Spatrick   while (!WorkList.empty()) {
235e5dd7070Spatrick     CFGBlock *Block = WorkList.pop_back_val();
236e5dd7070Spatrick 
237e5dd7070Spatrick     for (auto I = Block->succ_begin(), E = Block->succ_end(); I != E; ++I) {
238e5dd7070Spatrick       if (CFGBlock *SuccBlock = *I) {
239e5dd7070Spatrick         if (!Visited.insert(SuccBlock).second)
240e5dd7070Spatrick           continue;
241e5dd7070Spatrick 
242e5dd7070Spatrick         // Found a path to the exit node without a recursive call.
243e5dd7070Spatrick         if (ExitID == SuccBlock->getBlockID())
244e5dd7070Spatrick           return false;
245e5dd7070Spatrick 
246e5dd7070Spatrick         // If the successor block contains a recursive call, end analysis there.
247e5dd7070Spatrick         if (hasRecursiveCallInPath(FD, *SuccBlock)) {
248e5dd7070Spatrick           foundRecursion = true;
249e5dd7070Spatrick           continue;
250e5dd7070Spatrick         }
251e5dd7070Spatrick 
252e5dd7070Spatrick         WorkList.push_back(SuccBlock);
253e5dd7070Spatrick       }
254e5dd7070Spatrick     }
255e5dd7070Spatrick   }
256e5dd7070Spatrick   return foundRecursion;
257e5dd7070Spatrick }
258e5dd7070Spatrick 
checkRecursiveFunction(Sema & S,const FunctionDecl * FD,const Stmt * Body,AnalysisDeclContext & AC)259e5dd7070Spatrick static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,
260e5dd7070Spatrick                                    const Stmt *Body, AnalysisDeclContext &AC) {
261e5dd7070Spatrick   FD = FD->getCanonicalDecl();
262e5dd7070Spatrick 
263e5dd7070Spatrick   // Only run on non-templated functions and non-templated members of
264e5dd7070Spatrick   // templated classes.
265e5dd7070Spatrick   if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate &&
266e5dd7070Spatrick       FD->getTemplatedKind() != FunctionDecl::TK_MemberSpecialization)
267e5dd7070Spatrick     return;
268e5dd7070Spatrick 
269e5dd7070Spatrick   CFG *cfg = AC.getCFG();
270e5dd7070Spatrick   if (!cfg) return;
271e5dd7070Spatrick 
272e5dd7070Spatrick   // If the exit block is unreachable, skip processing the function.
273e5dd7070Spatrick   if (cfg->getExit().pred_empty())
274e5dd7070Spatrick     return;
275e5dd7070Spatrick 
276e5dd7070Spatrick   // Emit diagnostic if a recursive function call is detected for all paths.
277e5dd7070Spatrick   if (checkForRecursiveFunctionCall(FD, cfg))
278e5dd7070Spatrick     S.Diag(Body->getBeginLoc(), diag::warn_infinite_recursive_function);
279e5dd7070Spatrick }
280e5dd7070Spatrick 
281e5dd7070Spatrick //===----------------------------------------------------------------------===//
282e5dd7070Spatrick // Check for throw in a non-throwing function.
283e5dd7070Spatrick //===----------------------------------------------------------------------===//
284e5dd7070Spatrick 
285e5dd7070Spatrick /// Determine whether an exception thrown by E, unwinding from ThrowBlock,
286e5dd7070Spatrick /// can reach ExitBlock.
throwEscapes(Sema & S,const CXXThrowExpr * E,CFGBlock & ThrowBlock,CFG * Body)287e5dd7070Spatrick static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock,
288e5dd7070Spatrick                          CFG *Body) {
289e5dd7070Spatrick   SmallVector<CFGBlock *, 16> Stack;
290e5dd7070Spatrick   llvm::BitVector Queued(Body->getNumBlockIDs());
291e5dd7070Spatrick 
292e5dd7070Spatrick   Stack.push_back(&ThrowBlock);
293e5dd7070Spatrick   Queued[ThrowBlock.getBlockID()] = true;
294e5dd7070Spatrick 
295e5dd7070Spatrick   while (!Stack.empty()) {
296e5dd7070Spatrick     CFGBlock &UnwindBlock = *Stack.back();
297e5dd7070Spatrick     Stack.pop_back();
298e5dd7070Spatrick 
299e5dd7070Spatrick     for (auto &Succ : UnwindBlock.succs()) {
300e5dd7070Spatrick       if (!Succ.isReachable() || Queued[Succ->getBlockID()])
301e5dd7070Spatrick         continue;
302e5dd7070Spatrick 
303e5dd7070Spatrick       if (Succ->getBlockID() == Body->getExit().getBlockID())
304e5dd7070Spatrick         return true;
305e5dd7070Spatrick 
306e5dd7070Spatrick       if (auto *Catch =
307e5dd7070Spatrick               dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
308e5dd7070Spatrick         QualType Caught = Catch->getCaughtType();
309e5dd7070Spatrick         if (Caught.isNull() || // catch (...) catches everything
310e5dd7070Spatrick             !E->getSubExpr() || // throw; is considered cuaght by any handler
311e5dd7070Spatrick             S.handlerCanCatch(Caught, E->getSubExpr()->getType()))
312e5dd7070Spatrick           // Exception doesn't escape via this path.
313e5dd7070Spatrick           break;
314e5dd7070Spatrick       } else {
315e5dd7070Spatrick         Stack.push_back(Succ);
316e5dd7070Spatrick         Queued[Succ->getBlockID()] = true;
317e5dd7070Spatrick       }
318e5dd7070Spatrick     }
319e5dd7070Spatrick   }
320e5dd7070Spatrick 
321e5dd7070Spatrick   return false;
322e5dd7070Spatrick }
323e5dd7070Spatrick 
visitReachableThrows(CFG * BodyCFG,llvm::function_ref<void (const CXXThrowExpr *,CFGBlock &)> Visit)324e5dd7070Spatrick static void visitReachableThrows(
325e5dd7070Spatrick     CFG *BodyCFG,
326e5dd7070Spatrick     llvm::function_ref<void(const CXXThrowExpr *, CFGBlock &)> Visit) {
327e5dd7070Spatrick   llvm::BitVector Reachable(BodyCFG->getNumBlockIDs());
328e5dd7070Spatrick   clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(), Reachable);
329e5dd7070Spatrick   for (CFGBlock *B : *BodyCFG) {
330e5dd7070Spatrick     if (!Reachable[B->getBlockID()])
331e5dd7070Spatrick       continue;
332e5dd7070Spatrick     for (CFGElement &E : *B) {
333*12c85518Srobert       std::optional<CFGStmt> S = E.getAs<CFGStmt>();
334e5dd7070Spatrick       if (!S)
335e5dd7070Spatrick         continue;
336e5dd7070Spatrick       if (auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))
337e5dd7070Spatrick         Visit(Throw, *B);
338e5dd7070Spatrick     }
339e5dd7070Spatrick   }
340e5dd7070Spatrick }
341e5dd7070Spatrick 
EmitDiagForCXXThrowInNonThrowingFunc(Sema & S,SourceLocation OpLoc,const FunctionDecl * FD)342e5dd7070Spatrick static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc,
343e5dd7070Spatrick                                                  const FunctionDecl *FD) {
344e5dd7070Spatrick   if (!S.getSourceManager().isInSystemHeader(OpLoc) &&
345e5dd7070Spatrick       FD->getTypeSourceInfo()) {
346e5dd7070Spatrick     S.Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
347e5dd7070Spatrick     if (S.getLangOpts().CPlusPlus11 &&
348e5dd7070Spatrick         (isa<CXXDestructorDecl>(FD) ||
349e5dd7070Spatrick          FD->getDeclName().getCXXOverloadedOperator() == OO_Delete ||
350e5dd7070Spatrick          FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) {
351e5dd7070Spatrick       if (const auto *Ty = FD->getTypeSourceInfo()->getType()->
352e5dd7070Spatrick                                          getAs<FunctionProtoType>())
353e5dd7070Spatrick         S.Diag(FD->getLocation(), diag::note_throw_in_dtor)
354e5dd7070Spatrick             << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec()
355e5dd7070Spatrick             << FD->getExceptionSpecSourceRange();
356e5dd7070Spatrick     } else
357e5dd7070Spatrick       S.Diag(FD->getLocation(), diag::note_throw_in_function)
358e5dd7070Spatrick           << FD->getExceptionSpecSourceRange();
359e5dd7070Spatrick   }
360e5dd7070Spatrick }
361e5dd7070Spatrick 
checkThrowInNonThrowingFunc(Sema & S,const FunctionDecl * FD,AnalysisDeclContext & AC)362e5dd7070Spatrick static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD,
363e5dd7070Spatrick                                         AnalysisDeclContext &AC) {
364e5dd7070Spatrick   CFG *BodyCFG = AC.getCFG();
365e5dd7070Spatrick   if (!BodyCFG)
366e5dd7070Spatrick     return;
367e5dd7070Spatrick   if (BodyCFG->getExit().pred_empty())
368e5dd7070Spatrick     return;
369e5dd7070Spatrick   visitReachableThrows(BodyCFG, [&](const CXXThrowExpr *Throw, CFGBlock &Block) {
370e5dd7070Spatrick     if (throwEscapes(S, Throw, Block, BodyCFG))
371e5dd7070Spatrick       EmitDiagForCXXThrowInNonThrowingFunc(S, Throw->getThrowLoc(), FD);
372e5dd7070Spatrick   });
373e5dd7070Spatrick }
374e5dd7070Spatrick 
isNoexcept(const FunctionDecl * FD)375e5dd7070Spatrick static bool isNoexcept(const FunctionDecl *FD) {
376e5dd7070Spatrick   const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
377e5dd7070Spatrick   if (FPT->isNothrow() || FD->hasAttr<NoThrowAttr>())
378e5dd7070Spatrick     return true;
379e5dd7070Spatrick   return false;
380e5dd7070Spatrick }
381e5dd7070Spatrick 
382e5dd7070Spatrick //===----------------------------------------------------------------------===//
383e5dd7070Spatrick // Check for missing return value.
384e5dd7070Spatrick //===----------------------------------------------------------------------===//
385e5dd7070Spatrick 
386e5dd7070Spatrick enum ControlFlowKind {
387e5dd7070Spatrick   UnknownFallThrough,
388e5dd7070Spatrick   NeverFallThrough,
389e5dd7070Spatrick   MaybeFallThrough,
390e5dd7070Spatrick   AlwaysFallThrough,
391e5dd7070Spatrick   NeverFallThroughOrReturn
392e5dd7070Spatrick };
393e5dd7070Spatrick 
394e5dd7070Spatrick /// CheckFallThrough - Check that we don't fall off the end of a
395e5dd7070Spatrick /// Statement that should return a value.
396e5dd7070Spatrick ///
397e5dd7070Spatrick /// \returns AlwaysFallThrough iff we always fall off the end of the statement,
398e5dd7070Spatrick /// MaybeFallThrough iff we might or might not fall off the end,
399e5dd7070Spatrick /// NeverFallThroughOrReturn iff we never fall off the end of the statement or
400e5dd7070Spatrick /// return.  We assume NeverFallThrough iff we never fall off the end of the
401e5dd7070Spatrick /// statement but we may return.  We assume that functions not marked noreturn
402e5dd7070Spatrick /// will return.
CheckFallThrough(AnalysisDeclContext & AC)403e5dd7070Spatrick static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
404e5dd7070Spatrick   CFG *cfg = AC.getCFG();
405e5dd7070Spatrick   if (!cfg) return UnknownFallThrough;
406e5dd7070Spatrick 
407e5dd7070Spatrick   // The CFG leaves in dead things, and we don't want the dead code paths to
408e5dd7070Spatrick   // confuse us, so we mark all live things first.
409e5dd7070Spatrick   llvm::BitVector live(cfg->getNumBlockIDs());
410e5dd7070Spatrick   unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(),
411e5dd7070Spatrick                                                           live);
412e5dd7070Spatrick 
413e5dd7070Spatrick   bool AddEHEdges = AC.getAddEHEdges();
414e5dd7070Spatrick   if (!AddEHEdges && count != cfg->getNumBlockIDs())
415e5dd7070Spatrick     // When there are things remaining dead, and we didn't add EH edges
416e5dd7070Spatrick     // from CallExprs to the catch clauses, we have to go back and
417e5dd7070Spatrick     // mark them as live.
418e5dd7070Spatrick     for (const auto *B : *cfg) {
419e5dd7070Spatrick       if (!live[B->getBlockID()]) {
420e5dd7070Spatrick         if (B->pred_begin() == B->pred_end()) {
421e5dd7070Spatrick           const Stmt *Term = B->getTerminatorStmt();
422e5dd7070Spatrick           if (Term && isa<CXXTryStmt>(Term))
423e5dd7070Spatrick             // When not adding EH edges from calls, catch clauses
424e5dd7070Spatrick             // can otherwise seem dead.  Avoid noting them as dead.
425e5dd7070Spatrick             count += reachable_code::ScanReachableFromBlock(B, live);
426e5dd7070Spatrick           continue;
427e5dd7070Spatrick         }
428e5dd7070Spatrick       }
429e5dd7070Spatrick     }
430e5dd7070Spatrick 
431e5dd7070Spatrick   // Now we know what is live, we check the live precessors of the exit block
432e5dd7070Spatrick   // and look for fall through paths, being careful to ignore normal returns,
433e5dd7070Spatrick   // and exceptional paths.
434e5dd7070Spatrick   bool HasLiveReturn = false;
435e5dd7070Spatrick   bool HasFakeEdge = false;
436e5dd7070Spatrick   bool HasPlainEdge = false;
437e5dd7070Spatrick   bool HasAbnormalEdge = false;
438e5dd7070Spatrick 
439e5dd7070Spatrick   // Ignore default cases that aren't likely to be reachable because all
440e5dd7070Spatrick   // enums in a switch(X) have explicit case statements.
441e5dd7070Spatrick   CFGBlock::FilterOptions FO;
442e5dd7070Spatrick   FO.IgnoreDefaultsWithCoveredEnums = 1;
443e5dd7070Spatrick 
444e5dd7070Spatrick   for (CFGBlock::filtered_pred_iterator I =
445e5dd7070Spatrick            cfg->getExit().filtered_pred_start_end(FO);
446e5dd7070Spatrick        I.hasMore(); ++I) {
447e5dd7070Spatrick     const CFGBlock &B = **I;
448e5dd7070Spatrick     if (!live[B.getBlockID()])
449e5dd7070Spatrick       continue;
450e5dd7070Spatrick 
451e5dd7070Spatrick     // Skip blocks which contain an element marked as no-return. They don't
452e5dd7070Spatrick     // represent actually viable edges into the exit block, so mark them as
453e5dd7070Spatrick     // abnormal.
454e5dd7070Spatrick     if (B.hasNoReturnElement()) {
455e5dd7070Spatrick       HasAbnormalEdge = true;
456e5dd7070Spatrick       continue;
457e5dd7070Spatrick     }
458e5dd7070Spatrick 
459e5dd7070Spatrick     // Destructors can appear after the 'return' in the CFG.  This is
460e5dd7070Spatrick     // normal.  We need to look pass the destructors for the return
461e5dd7070Spatrick     // statement (if it exists).
462e5dd7070Spatrick     CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend();
463e5dd7070Spatrick 
464e5dd7070Spatrick     for ( ; ri != re ; ++ri)
465e5dd7070Spatrick       if (ri->getAs<CFGStmt>())
466e5dd7070Spatrick         break;
467e5dd7070Spatrick 
468e5dd7070Spatrick     // No more CFGElements in the block?
469e5dd7070Spatrick     if (ri == re) {
470e5dd7070Spatrick       const Stmt *Term = B.getTerminatorStmt();
471*12c85518Srobert       if (Term && (isa<CXXTryStmt>(Term) || isa<ObjCAtTryStmt>(Term))) {
472e5dd7070Spatrick         HasAbnormalEdge = true;
473e5dd7070Spatrick         continue;
474e5dd7070Spatrick       }
475e5dd7070Spatrick       // A labeled empty statement, or the entry block...
476e5dd7070Spatrick       HasPlainEdge = true;
477e5dd7070Spatrick       continue;
478e5dd7070Spatrick     }
479e5dd7070Spatrick 
480e5dd7070Spatrick     CFGStmt CS = ri->castAs<CFGStmt>();
481e5dd7070Spatrick     const Stmt *S = CS.getStmt();
482e5dd7070Spatrick     if (isa<ReturnStmt>(S) || isa<CoreturnStmt>(S)) {
483e5dd7070Spatrick       HasLiveReturn = true;
484e5dd7070Spatrick       continue;
485e5dd7070Spatrick     }
486e5dd7070Spatrick     if (isa<ObjCAtThrowStmt>(S)) {
487e5dd7070Spatrick       HasFakeEdge = true;
488e5dd7070Spatrick       continue;
489e5dd7070Spatrick     }
490e5dd7070Spatrick     if (isa<CXXThrowExpr>(S)) {
491e5dd7070Spatrick       HasFakeEdge = true;
492e5dd7070Spatrick       continue;
493e5dd7070Spatrick     }
494e5dd7070Spatrick     if (isa<MSAsmStmt>(S)) {
495e5dd7070Spatrick       // TODO: Verify this is correct.
496e5dd7070Spatrick       HasFakeEdge = true;
497e5dd7070Spatrick       HasLiveReturn = true;
498e5dd7070Spatrick       continue;
499e5dd7070Spatrick     }
500e5dd7070Spatrick     if (isa<CXXTryStmt>(S)) {
501e5dd7070Spatrick       HasAbnormalEdge = true;
502e5dd7070Spatrick       continue;
503e5dd7070Spatrick     }
504*12c85518Srobert     if (!llvm::is_contained(B.succs(), &cfg->getExit())) {
505e5dd7070Spatrick       HasAbnormalEdge = true;
506e5dd7070Spatrick       continue;
507e5dd7070Spatrick     }
508e5dd7070Spatrick 
509e5dd7070Spatrick     HasPlainEdge = true;
510e5dd7070Spatrick   }
511e5dd7070Spatrick   if (!HasPlainEdge) {
512e5dd7070Spatrick     if (HasLiveReturn)
513e5dd7070Spatrick       return NeverFallThrough;
514e5dd7070Spatrick     return NeverFallThroughOrReturn;
515e5dd7070Spatrick   }
516e5dd7070Spatrick   if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
517e5dd7070Spatrick     return MaybeFallThrough;
518e5dd7070Spatrick   // This says AlwaysFallThrough for calls to functions that are not marked
519e5dd7070Spatrick   // noreturn, that don't return.  If people would like this warning to be more
520e5dd7070Spatrick   // accurate, such functions should be marked as noreturn.
521e5dd7070Spatrick   return AlwaysFallThrough;
522e5dd7070Spatrick }
523e5dd7070Spatrick 
524e5dd7070Spatrick namespace {
525e5dd7070Spatrick 
526e5dd7070Spatrick struct CheckFallThroughDiagnostics {
527e5dd7070Spatrick   unsigned diag_MaybeFallThrough_HasNoReturn;
528e5dd7070Spatrick   unsigned diag_MaybeFallThrough_ReturnsNonVoid;
529e5dd7070Spatrick   unsigned diag_AlwaysFallThrough_HasNoReturn;
530e5dd7070Spatrick   unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
531e5dd7070Spatrick   unsigned diag_NeverFallThroughOrReturn;
532e5dd7070Spatrick   enum { Function, Block, Lambda, Coroutine } funMode;
533e5dd7070Spatrick   SourceLocation FuncLoc;
534e5dd7070Spatrick 
MakeForFunction__anon27fad7f20411::CheckFallThroughDiagnostics535e5dd7070Spatrick   static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) {
536e5dd7070Spatrick     CheckFallThroughDiagnostics D;
537e5dd7070Spatrick     D.FuncLoc = Func->getLocation();
538e5dd7070Spatrick     D.diag_MaybeFallThrough_HasNoReturn =
539e5dd7070Spatrick       diag::warn_falloff_noreturn_function;
540e5dd7070Spatrick     D.diag_MaybeFallThrough_ReturnsNonVoid =
541e5dd7070Spatrick       diag::warn_maybe_falloff_nonvoid_function;
542e5dd7070Spatrick     D.diag_AlwaysFallThrough_HasNoReturn =
543e5dd7070Spatrick       diag::warn_falloff_noreturn_function;
544e5dd7070Spatrick     D.diag_AlwaysFallThrough_ReturnsNonVoid =
545e5dd7070Spatrick       diag::warn_falloff_nonvoid_function;
546e5dd7070Spatrick 
547e5dd7070Spatrick     // Don't suggest that virtual functions be marked "noreturn", since they
548e5dd7070Spatrick     // might be overridden by non-noreturn functions.
549e5dd7070Spatrick     bool isVirtualMethod = false;
550e5dd7070Spatrick     if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func))
551e5dd7070Spatrick       isVirtualMethod = Method->isVirtual();
552e5dd7070Spatrick 
553e5dd7070Spatrick     // Don't suggest that template instantiations be marked "noreturn"
554e5dd7070Spatrick     bool isTemplateInstantiation = false;
555e5dd7070Spatrick     if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func))
556e5dd7070Spatrick       isTemplateInstantiation = Function->isTemplateInstantiation();
557e5dd7070Spatrick 
558e5dd7070Spatrick     if (!isVirtualMethod && !isTemplateInstantiation)
559e5dd7070Spatrick       D.diag_NeverFallThroughOrReturn =
560e5dd7070Spatrick         diag::warn_suggest_noreturn_function;
561e5dd7070Spatrick     else
562e5dd7070Spatrick       D.diag_NeverFallThroughOrReturn = 0;
563e5dd7070Spatrick 
564e5dd7070Spatrick     D.funMode = Function;
565e5dd7070Spatrick     return D;
566e5dd7070Spatrick   }
567e5dd7070Spatrick 
MakeForCoroutine__anon27fad7f20411::CheckFallThroughDiagnostics568e5dd7070Spatrick   static CheckFallThroughDiagnostics MakeForCoroutine(const Decl *Func) {
569e5dd7070Spatrick     CheckFallThroughDiagnostics D;
570e5dd7070Spatrick     D.FuncLoc = Func->getLocation();
571e5dd7070Spatrick     D.diag_MaybeFallThrough_HasNoReturn = 0;
572e5dd7070Spatrick     D.diag_MaybeFallThrough_ReturnsNonVoid =
573e5dd7070Spatrick         diag::warn_maybe_falloff_nonvoid_coroutine;
574e5dd7070Spatrick     D.diag_AlwaysFallThrough_HasNoReturn = 0;
575e5dd7070Spatrick     D.diag_AlwaysFallThrough_ReturnsNonVoid =
576e5dd7070Spatrick         diag::warn_falloff_nonvoid_coroutine;
577e5dd7070Spatrick     D.funMode = Coroutine;
578e5dd7070Spatrick     return D;
579e5dd7070Spatrick   }
580e5dd7070Spatrick 
MakeForBlock__anon27fad7f20411::CheckFallThroughDiagnostics581e5dd7070Spatrick   static CheckFallThroughDiagnostics MakeForBlock() {
582e5dd7070Spatrick     CheckFallThroughDiagnostics D;
583e5dd7070Spatrick     D.diag_MaybeFallThrough_HasNoReturn =
584e5dd7070Spatrick       diag::err_noreturn_block_has_return_expr;
585e5dd7070Spatrick     D.diag_MaybeFallThrough_ReturnsNonVoid =
586e5dd7070Spatrick       diag::err_maybe_falloff_nonvoid_block;
587e5dd7070Spatrick     D.diag_AlwaysFallThrough_HasNoReturn =
588e5dd7070Spatrick       diag::err_noreturn_block_has_return_expr;
589e5dd7070Spatrick     D.diag_AlwaysFallThrough_ReturnsNonVoid =
590e5dd7070Spatrick       diag::err_falloff_nonvoid_block;
591e5dd7070Spatrick     D.diag_NeverFallThroughOrReturn = 0;
592e5dd7070Spatrick     D.funMode = Block;
593e5dd7070Spatrick     return D;
594e5dd7070Spatrick   }
595e5dd7070Spatrick 
MakeForLambda__anon27fad7f20411::CheckFallThroughDiagnostics596e5dd7070Spatrick   static CheckFallThroughDiagnostics MakeForLambda() {
597e5dd7070Spatrick     CheckFallThroughDiagnostics D;
598e5dd7070Spatrick     D.diag_MaybeFallThrough_HasNoReturn =
599e5dd7070Spatrick       diag::err_noreturn_lambda_has_return_expr;
600e5dd7070Spatrick     D.diag_MaybeFallThrough_ReturnsNonVoid =
601e5dd7070Spatrick       diag::warn_maybe_falloff_nonvoid_lambda;
602e5dd7070Spatrick     D.diag_AlwaysFallThrough_HasNoReturn =
603e5dd7070Spatrick       diag::err_noreturn_lambda_has_return_expr;
604e5dd7070Spatrick     D.diag_AlwaysFallThrough_ReturnsNonVoid =
605e5dd7070Spatrick       diag::warn_falloff_nonvoid_lambda;
606e5dd7070Spatrick     D.diag_NeverFallThroughOrReturn = 0;
607e5dd7070Spatrick     D.funMode = Lambda;
608e5dd7070Spatrick     return D;
609e5dd7070Spatrick   }
610e5dd7070Spatrick 
checkDiagnostics__anon27fad7f20411::CheckFallThroughDiagnostics611e5dd7070Spatrick   bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid,
612e5dd7070Spatrick                         bool HasNoReturn) const {
613e5dd7070Spatrick     if (funMode == Function) {
614e5dd7070Spatrick       return (ReturnsVoid ||
615e5dd7070Spatrick               D.isIgnored(diag::warn_maybe_falloff_nonvoid_function,
616e5dd7070Spatrick                           FuncLoc)) &&
617e5dd7070Spatrick              (!HasNoReturn ||
618e5dd7070Spatrick               D.isIgnored(diag::warn_noreturn_function_has_return_expr,
619e5dd7070Spatrick                           FuncLoc)) &&
620e5dd7070Spatrick              (!ReturnsVoid ||
621e5dd7070Spatrick               D.isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));
622e5dd7070Spatrick     }
623e5dd7070Spatrick     if (funMode == Coroutine) {
624e5dd7070Spatrick       return (ReturnsVoid ||
625e5dd7070Spatrick               D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, FuncLoc) ||
626e5dd7070Spatrick               D.isIgnored(diag::warn_maybe_falloff_nonvoid_coroutine,
627e5dd7070Spatrick                           FuncLoc)) &&
628e5dd7070Spatrick              (!HasNoReturn);
629e5dd7070Spatrick     }
630e5dd7070Spatrick     // For blocks / lambdas.
631e5dd7070Spatrick     return ReturnsVoid && !HasNoReturn;
632e5dd7070Spatrick   }
633e5dd7070Spatrick };
634e5dd7070Spatrick 
635e5dd7070Spatrick } // anonymous namespace
636e5dd7070Spatrick 
637e5dd7070Spatrick /// CheckFallThroughForBody - Check that we don't fall off the end of a
638e5dd7070Spatrick /// function that should return a value.  Check that we don't fall off the end
639e5dd7070Spatrick /// of a noreturn function.  We assume that functions and blocks not marked
640e5dd7070Spatrick /// noreturn will return.
CheckFallThroughForBody(Sema & S,const Decl * D,const Stmt * Body,QualType BlockType,const CheckFallThroughDiagnostics & CD,AnalysisDeclContext & AC,sema::FunctionScopeInfo * FSI)641e5dd7070Spatrick static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
642e5dd7070Spatrick                                     QualType BlockType,
643e5dd7070Spatrick                                     const CheckFallThroughDiagnostics &CD,
644e5dd7070Spatrick                                     AnalysisDeclContext &AC,
645e5dd7070Spatrick                                     sema::FunctionScopeInfo *FSI) {
646e5dd7070Spatrick 
647e5dd7070Spatrick   bool ReturnsVoid = false;
648e5dd7070Spatrick   bool HasNoReturn = false;
649e5dd7070Spatrick   bool IsCoroutine = FSI->isCoroutine();
650e5dd7070Spatrick 
651e5dd7070Spatrick   if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
652e5dd7070Spatrick     if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
653e5dd7070Spatrick       ReturnsVoid = CBody->getFallthroughHandler() != nullptr;
654e5dd7070Spatrick     else
655e5dd7070Spatrick       ReturnsVoid = FD->getReturnType()->isVoidType();
656e5dd7070Spatrick     HasNoReturn = FD->isNoReturn();
657e5dd7070Spatrick   }
658e5dd7070Spatrick   else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
659e5dd7070Spatrick     ReturnsVoid = MD->getReturnType()->isVoidType();
660e5dd7070Spatrick     HasNoReturn = MD->hasAttr<NoReturnAttr>();
661e5dd7070Spatrick   }
662e5dd7070Spatrick   else if (isa<BlockDecl>(D)) {
663e5dd7070Spatrick     if (const FunctionType *FT =
664e5dd7070Spatrick           BlockType->getPointeeType()->getAs<FunctionType>()) {
665e5dd7070Spatrick       if (FT->getReturnType()->isVoidType())
666e5dd7070Spatrick         ReturnsVoid = true;
667e5dd7070Spatrick       if (FT->getNoReturnAttr())
668e5dd7070Spatrick         HasNoReturn = true;
669e5dd7070Spatrick     }
670e5dd7070Spatrick   }
671e5dd7070Spatrick 
672e5dd7070Spatrick   DiagnosticsEngine &Diags = S.getDiagnostics();
673e5dd7070Spatrick 
674e5dd7070Spatrick   // Short circuit for compilation speed.
675e5dd7070Spatrick   if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
676e5dd7070Spatrick       return;
677e5dd7070Spatrick   SourceLocation LBrace = Body->getBeginLoc(), RBrace = Body->getEndLoc();
678e5dd7070Spatrick   auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) {
679e5dd7070Spatrick     if (IsCoroutine)
680e5dd7070Spatrick       S.Diag(Loc, DiagID) << FSI->CoroutinePromise->getType();
681e5dd7070Spatrick     else
682e5dd7070Spatrick       S.Diag(Loc, DiagID);
683e5dd7070Spatrick   };
684e5dd7070Spatrick 
685e5dd7070Spatrick   // cpu_dispatch functions permit empty function bodies for ICC compatibility.
686e5dd7070Spatrick   if (D->getAsFunction() && D->getAsFunction()->isCPUDispatchMultiVersion())
687e5dd7070Spatrick     return;
688e5dd7070Spatrick 
689e5dd7070Spatrick   // Either in a function body compound statement, or a function-try-block.
690e5dd7070Spatrick   switch (CheckFallThrough(AC)) {
691e5dd7070Spatrick     case UnknownFallThrough:
692e5dd7070Spatrick       break;
693e5dd7070Spatrick 
694e5dd7070Spatrick     case MaybeFallThrough:
695e5dd7070Spatrick       if (HasNoReturn)
696e5dd7070Spatrick         EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);
697e5dd7070Spatrick       else if (!ReturnsVoid)
698e5dd7070Spatrick         EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);
699e5dd7070Spatrick       break;
700e5dd7070Spatrick     case AlwaysFallThrough:
701e5dd7070Spatrick       if (HasNoReturn)
702e5dd7070Spatrick         EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);
703e5dd7070Spatrick       else if (!ReturnsVoid)
704e5dd7070Spatrick         EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
705e5dd7070Spatrick       break;
706e5dd7070Spatrick     case NeverFallThroughOrReturn:
707e5dd7070Spatrick       if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
708e5dd7070Spatrick         if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
709e5dd7070Spatrick           S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
710e5dd7070Spatrick         } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
711e5dd7070Spatrick           S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
712e5dd7070Spatrick         } else {
713e5dd7070Spatrick           S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
714e5dd7070Spatrick         }
715e5dd7070Spatrick       }
716e5dd7070Spatrick       break;
717e5dd7070Spatrick     case NeverFallThrough:
718e5dd7070Spatrick       break;
719e5dd7070Spatrick   }
720e5dd7070Spatrick }
721e5dd7070Spatrick 
722e5dd7070Spatrick //===----------------------------------------------------------------------===//
723e5dd7070Spatrick // -Wuninitialized
724e5dd7070Spatrick //===----------------------------------------------------------------------===//
725e5dd7070Spatrick 
726e5dd7070Spatrick namespace {
727e5dd7070Spatrick /// ContainsReference - A visitor class to search for references to
728e5dd7070Spatrick /// a particular declaration (the needle) within any evaluated component of an
729e5dd7070Spatrick /// expression (recursively).
730e5dd7070Spatrick class ContainsReference : public ConstEvaluatedExprVisitor<ContainsReference> {
731e5dd7070Spatrick   bool FoundReference;
732e5dd7070Spatrick   const DeclRefExpr *Needle;
733e5dd7070Spatrick 
734e5dd7070Spatrick public:
735e5dd7070Spatrick   typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited;
736e5dd7070Spatrick 
ContainsReference(ASTContext & Context,const DeclRefExpr * Needle)737e5dd7070Spatrick   ContainsReference(ASTContext &Context, const DeclRefExpr *Needle)
738e5dd7070Spatrick     : Inherited(Context), FoundReference(false), Needle(Needle) {}
739e5dd7070Spatrick 
VisitExpr(const Expr * E)740e5dd7070Spatrick   void VisitExpr(const Expr *E) {
741e5dd7070Spatrick     // Stop evaluating if we already have a reference.
742e5dd7070Spatrick     if (FoundReference)
743e5dd7070Spatrick       return;
744e5dd7070Spatrick 
745e5dd7070Spatrick     Inherited::VisitExpr(E);
746e5dd7070Spatrick   }
747e5dd7070Spatrick 
VisitDeclRefExpr(const DeclRefExpr * E)748e5dd7070Spatrick   void VisitDeclRefExpr(const DeclRefExpr *E) {
749e5dd7070Spatrick     if (E == Needle)
750e5dd7070Spatrick       FoundReference = true;
751e5dd7070Spatrick     else
752e5dd7070Spatrick       Inherited::VisitDeclRefExpr(E);
753e5dd7070Spatrick   }
754e5dd7070Spatrick 
doesContainReference() const755e5dd7070Spatrick   bool doesContainReference() const { return FoundReference; }
756e5dd7070Spatrick };
757e5dd7070Spatrick } // anonymous namespace
758e5dd7070Spatrick 
SuggestInitializationFixit(Sema & S,const VarDecl * VD)759e5dd7070Spatrick static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
760e5dd7070Spatrick   QualType VariableTy = VD->getType().getCanonicalType();
761e5dd7070Spatrick   if (VariableTy->isBlockPointerType() &&
762e5dd7070Spatrick       !VD->hasAttr<BlocksAttr>()) {
763e5dd7070Spatrick     S.Diag(VD->getLocation(), diag::note_block_var_fixit_add_initialization)
764e5dd7070Spatrick         << VD->getDeclName()
765e5dd7070Spatrick         << FixItHint::CreateInsertion(VD->getLocation(), "__block ");
766e5dd7070Spatrick     return true;
767e5dd7070Spatrick   }
768e5dd7070Spatrick 
769e5dd7070Spatrick   // Don't issue a fixit if there is already an initializer.
770e5dd7070Spatrick   if (VD->getInit())
771e5dd7070Spatrick     return false;
772e5dd7070Spatrick 
773e5dd7070Spatrick   // Don't suggest a fixit inside macros.
774e5dd7070Spatrick   if (VD->getEndLoc().isMacroID())
775e5dd7070Spatrick     return false;
776e5dd7070Spatrick 
777e5dd7070Spatrick   SourceLocation Loc = S.getLocForEndOfToken(VD->getEndLoc());
778e5dd7070Spatrick 
779e5dd7070Spatrick   // Suggest possible initialization (if any).
780e5dd7070Spatrick   std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc);
781e5dd7070Spatrick   if (Init.empty())
782e5dd7070Spatrick     return false;
783e5dd7070Spatrick 
784e5dd7070Spatrick   S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName()
785e5dd7070Spatrick     << FixItHint::CreateInsertion(Loc, Init);
786e5dd7070Spatrick   return true;
787e5dd7070Spatrick }
788e5dd7070Spatrick 
789e5dd7070Spatrick /// Create a fixit to remove an if-like statement, on the assumption that its
790e5dd7070Spatrick /// condition is CondVal.
CreateIfFixit(Sema & S,const Stmt * If,const Stmt * Then,const Stmt * Else,bool CondVal,FixItHint & Fixit1,FixItHint & Fixit2)791e5dd7070Spatrick static void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then,
792e5dd7070Spatrick                           const Stmt *Else, bool CondVal,
793e5dd7070Spatrick                           FixItHint &Fixit1, FixItHint &Fixit2) {
794e5dd7070Spatrick   if (CondVal) {
795e5dd7070Spatrick     // If condition is always true, remove all but the 'then'.
796e5dd7070Spatrick     Fixit1 = FixItHint::CreateRemoval(
797e5dd7070Spatrick         CharSourceRange::getCharRange(If->getBeginLoc(), Then->getBeginLoc()));
798e5dd7070Spatrick     if (Else) {
799e5dd7070Spatrick       SourceLocation ElseKwLoc = S.getLocForEndOfToken(Then->getEndLoc());
800e5dd7070Spatrick       Fixit2 =
801e5dd7070Spatrick           FixItHint::CreateRemoval(SourceRange(ElseKwLoc, Else->getEndLoc()));
802e5dd7070Spatrick     }
803e5dd7070Spatrick   } else {
804e5dd7070Spatrick     // If condition is always false, remove all but the 'else'.
805e5dd7070Spatrick     if (Else)
806e5dd7070Spatrick       Fixit1 = FixItHint::CreateRemoval(CharSourceRange::getCharRange(
807e5dd7070Spatrick           If->getBeginLoc(), Else->getBeginLoc()));
808e5dd7070Spatrick     else
809e5dd7070Spatrick       Fixit1 = FixItHint::CreateRemoval(If->getSourceRange());
810e5dd7070Spatrick   }
811e5dd7070Spatrick }
812e5dd7070Spatrick 
813e5dd7070Spatrick /// DiagUninitUse -- Helper function to produce a diagnostic for an
814e5dd7070Spatrick /// uninitialized use of a variable.
DiagUninitUse(Sema & S,const VarDecl * VD,const UninitUse & Use,bool IsCapturedByBlock)815e5dd7070Spatrick static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
816e5dd7070Spatrick                           bool IsCapturedByBlock) {
817e5dd7070Spatrick   bool Diagnosed = false;
818e5dd7070Spatrick 
819e5dd7070Spatrick   switch (Use.getKind()) {
820e5dd7070Spatrick   case UninitUse::Always:
821e5dd7070Spatrick     S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_var)
822e5dd7070Spatrick         << VD->getDeclName() << IsCapturedByBlock
823e5dd7070Spatrick         << Use.getUser()->getSourceRange();
824e5dd7070Spatrick     return;
825e5dd7070Spatrick 
826e5dd7070Spatrick   case UninitUse::AfterDecl:
827e5dd7070Spatrick   case UninitUse::AfterCall:
828e5dd7070Spatrick     S.Diag(VD->getLocation(), diag::warn_sometimes_uninit_var)
829e5dd7070Spatrick       << VD->getDeclName() << IsCapturedByBlock
830e5dd7070Spatrick       << (Use.getKind() == UninitUse::AfterDecl ? 4 : 5)
831e5dd7070Spatrick       << const_cast<DeclContext*>(VD->getLexicalDeclContext())
832e5dd7070Spatrick       << VD->getSourceRange();
833e5dd7070Spatrick     S.Diag(Use.getUser()->getBeginLoc(), diag::note_uninit_var_use)
834e5dd7070Spatrick         << IsCapturedByBlock << Use.getUser()->getSourceRange();
835e5dd7070Spatrick     return;
836e5dd7070Spatrick 
837e5dd7070Spatrick   case UninitUse::Maybe:
838e5dd7070Spatrick   case UninitUse::Sometimes:
839e5dd7070Spatrick     // Carry on to report sometimes-uninitialized branches, if possible,
840e5dd7070Spatrick     // or a 'may be used uninitialized' diagnostic otherwise.
841e5dd7070Spatrick     break;
842e5dd7070Spatrick   }
843e5dd7070Spatrick 
844e5dd7070Spatrick   // Diagnose each branch which leads to a sometimes-uninitialized use.
845e5dd7070Spatrick   for (UninitUse::branch_iterator I = Use.branch_begin(), E = Use.branch_end();
846e5dd7070Spatrick        I != E; ++I) {
847e5dd7070Spatrick     assert(Use.getKind() == UninitUse::Sometimes);
848e5dd7070Spatrick 
849e5dd7070Spatrick     const Expr *User = Use.getUser();
850e5dd7070Spatrick     const Stmt *Term = I->Terminator;
851e5dd7070Spatrick 
852e5dd7070Spatrick     // Information used when building the diagnostic.
853e5dd7070Spatrick     unsigned DiagKind;
854e5dd7070Spatrick     StringRef Str;
855e5dd7070Spatrick     SourceRange Range;
856e5dd7070Spatrick 
857e5dd7070Spatrick     // FixIts to suppress the diagnostic by removing the dead condition.
858e5dd7070Spatrick     // For all binary terminators, branch 0 is taken if the condition is true,
859e5dd7070Spatrick     // and branch 1 is taken if the condition is false.
860e5dd7070Spatrick     int RemoveDiagKind = -1;
861e5dd7070Spatrick     const char *FixitStr =
862e5dd7070Spatrick         S.getLangOpts().CPlusPlus ? (I->Output ? "true" : "false")
863e5dd7070Spatrick                                   : (I->Output ? "1" : "0");
864e5dd7070Spatrick     FixItHint Fixit1, Fixit2;
865e5dd7070Spatrick 
866e5dd7070Spatrick     switch (Term ? Term->getStmtClass() : Stmt::DeclStmtClass) {
867e5dd7070Spatrick     default:
868e5dd7070Spatrick       // Don't know how to report this. Just fall back to 'may be used
869e5dd7070Spatrick       // uninitialized'. FIXME: Can this happen?
870e5dd7070Spatrick       continue;
871e5dd7070Spatrick 
872e5dd7070Spatrick     // "condition is true / condition is false".
873e5dd7070Spatrick     case Stmt::IfStmtClass: {
874e5dd7070Spatrick       const IfStmt *IS = cast<IfStmt>(Term);
875e5dd7070Spatrick       DiagKind = 0;
876e5dd7070Spatrick       Str = "if";
877e5dd7070Spatrick       Range = IS->getCond()->getSourceRange();
878e5dd7070Spatrick       RemoveDiagKind = 0;
879e5dd7070Spatrick       CreateIfFixit(S, IS, IS->getThen(), IS->getElse(),
880e5dd7070Spatrick                     I->Output, Fixit1, Fixit2);
881e5dd7070Spatrick       break;
882e5dd7070Spatrick     }
883e5dd7070Spatrick     case Stmt::ConditionalOperatorClass: {
884e5dd7070Spatrick       const ConditionalOperator *CO = cast<ConditionalOperator>(Term);
885e5dd7070Spatrick       DiagKind = 0;
886e5dd7070Spatrick       Str = "?:";
887e5dd7070Spatrick       Range = CO->getCond()->getSourceRange();
888e5dd7070Spatrick       RemoveDiagKind = 0;
889e5dd7070Spatrick       CreateIfFixit(S, CO, CO->getTrueExpr(), CO->getFalseExpr(),
890e5dd7070Spatrick                     I->Output, Fixit1, Fixit2);
891e5dd7070Spatrick       break;
892e5dd7070Spatrick     }
893e5dd7070Spatrick     case Stmt::BinaryOperatorClass: {
894e5dd7070Spatrick       const BinaryOperator *BO = cast<BinaryOperator>(Term);
895e5dd7070Spatrick       if (!BO->isLogicalOp())
896e5dd7070Spatrick         continue;
897e5dd7070Spatrick       DiagKind = 0;
898e5dd7070Spatrick       Str = BO->getOpcodeStr();
899e5dd7070Spatrick       Range = BO->getLHS()->getSourceRange();
900e5dd7070Spatrick       RemoveDiagKind = 0;
901e5dd7070Spatrick       if ((BO->getOpcode() == BO_LAnd && I->Output) ||
902e5dd7070Spatrick           (BO->getOpcode() == BO_LOr && !I->Output))
903e5dd7070Spatrick         // true && y -> y, false || y -> y.
904e5dd7070Spatrick         Fixit1 = FixItHint::CreateRemoval(
905e5dd7070Spatrick             SourceRange(BO->getBeginLoc(), BO->getOperatorLoc()));
906e5dd7070Spatrick       else
907e5dd7070Spatrick         // false && y -> false, true || y -> true.
908e5dd7070Spatrick         Fixit1 = FixItHint::CreateReplacement(BO->getSourceRange(), FixitStr);
909e5dd7070Spatrick       break;
910e5dd7070Spatrick     }
911e5dd7070Spatrick 
912e5dd7070Spatrick     // "loop is entered / loop is exited".
913e5dd7070Spatrick     case Stmt::WhileStmtClass:
914e5dd7070Spatrick       DiagKind = 1;
915e5dd7070Spatrick       Str = "while";
916e5dd7070Spatrick       Range = cast<WhileStmt>(Term)->getCond()->getSourceRange();
917e5dd7070Spatrick       RemoveDiagKind = 1;
918e5dd7070Spatrick       Fixit1 = FixItHint::CreateReplacement(Range, FixitStr);
919e5dd7070Spatrick       break;
920e5dd7070Spatrick     case Stmt::ForStmtClass:
921e5dd7070Spatrick       DiagKind = 1;
922e5dd7070Spatrick       Str = "for";
923e5dd7070Spatrick       Range = cast<ForStmt>(Term)->getCond()->getSourceRange();
924e5dd7070Spatrick       RemoveDiagKind = 1;
925e5dd7070Spatrick       if (I->Output)
926e5dd7070Spatrick         Fixit1 = FixItHint::CreateRemoval(Range);
927e5dd7070Spatrick       else
928e5dd7070Spatrick         Fixit1 = FixItHint::CreateReplacement(Range, FixitStr);
929e5dd7070Spatrick       break;
930e5dd7070Spatrick     case Stmt::CXXForRangeStmtClass:
931e5dd7070Spatrick       if (I->Output == 1) {
932e5dd7070Spatrick         // The use occurs if a range-based for loop's body never executes.
933e5dd7070Spatrick         // That may be impossible, and there's no syntactic fix for this,
934e5dd7070Spatrick         // so treat it as a 'may be uninitialized' case.
935e5dd7070Spatrick         continue;
936e5dd7070Spatrick       }
937e5dd7070Spatrick       DiagKind = 1;
938e5dd7070Spatrick       Str = "for";
939e5dd7070Spatrick       Range = cast<CXXForRangeStmt>(Term)->getRangeInit()->getSourceRange();
940e5dd7070Spatrick       break;
941e5dd7070Spatrick 
942e5dd7070Spatrick     // "condition is true / loop is exited".
943e5dd7070Spatrick     case Stmt::DoStmtClass:
944e5dd7070Spatrick       DiagKind = 2;
945e5dd7070Spatrick       Str = "do";
946e5dd7070Spatrick       Range = cast<DoStmt>(Term)->getCond()->getSourceRange();
947e5dd7070Spatrick       RemoveDiagKind = 1;
948e5dd7070Spatrick       Fixit1 = FixItHint::CreateReplacement(Range, FixitStr);
949e5dd7070Spatrick       break;
950e5dd7070Spatrick 
951e5dd7070Spatrick     // "switch case is taken".
952e5dd7070Spatrick     case Stmt::CaseStmtClass:
953e5dd7070Spatrick       DiagKind = 3;
954e5dd7070Spatrick       Str = "case";
955e5dd7070Spatrick       Range = cast<CaseStmt>(Term)->getLHS()->getSourceRange();
956e5dd7070Spatrick       break;
957e5dd7070Spatrick     case Stmt::DefaultStmtClass:
958e5dd7070Spatrick       DiagKind = 3;
959e5dd7070Spatrick       Str = "default";
960e5dd7070Spatrick       Range = cast<DefaultStmt>(Term)->getDefaultLoc();
961e5dd7070Spatrick       break;
962e5dd7070Spatrick     }
963e5dd7070Spatrick 
964e5dd7070Spatrick     S.Diag(Range.getBegin(), diag::warn_sometimes_uninit_var)
965e5dd7070Spatrick       << VD->getDeclName() << IsCapturedByBlock << DiagKind
966e5dd7070Spatrick       << Str << I->Output << Range;
967e5dd7070Spatrick     S.Diag(User->getBeginLoc(), diag::note_uninit_var_use)
968e5dd7070Spatrick         << IsCapturedByBlock << User->getSourceRange();
969e5dd7070Spatrick     if (RemoveDiagKind != -1)
970e5dd7070Spatrick       S.Diag(Fixit1.RemoveRange.getBegin(), diag::note_uninit_fixit_remove_cond)
971e5dd7070Spatrick         << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
972e5dd7070Spatrick 
973e5dd7070Spatrick     Diagnosed = true;
974e5dd7070Spatrick   }
975e5dd7070Spatrick 
976e5dd7070Spatrick   if (!Diagnosed)
977e5dd7070Spatrick     S.Diag(Use.getUser()->getBeginLoc(), diag::warn_maybe_uninit_var)
978e5dd7070Spatrick         << VD->getDeclName() << IsCapturedByBlock
979e5dd7070Spatrick         << Use.getUser()->getSourceRange();
980e5dd7070Spatrick }
981e5dd7070Spatrick 
982ec727ea7Spatrick /// Diagnose uninitialized const reference usages.
DiagnoseUninitializedConstRefUse(Sema & S,const VarDecl * VD,const UninitUse & Use)983ec727ea7Spatrick static bool DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD,
984ec727ea7Spatrick                                              const UninitUse &Use) {
985ec727ea7Spatrick   S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_const_reference)
986ec727ea7Spatrick       << VD->getDeclName() << Use.getUser()->getSourceRange();
987ec727ea7Spatrick   return true;
988ec727ea7Spatrick }
989ec727ea7Spatrick 
990e5dd7070Spatrick /// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an
991e5dd7070Spatrick /// uninitialized variable. This manages the different forms of diagnostic
992e5dd7070Spatrick /// emitted for particular types of uses. Returns true if the use was diagnosed
993e5dd7070Spatrick /// as a warning. If a particular use is one we omit warnings for, returns
994e5dd7070Spatrick /// false.
DiagnoseUninitializedUse(Sema & S,const VarDecl * VD,const UninitUse & Use,bool alwaysReportSelfInit=false)995e5dd7070Spatrick static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
996e5dd7070Spatrick                                      const UninitUse &Use,
997e5dd7070Spatrick                                      bool alwaysReportSelfInit = false) {
998e5dd7070Spatrick   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Use.getUser())) {
999e5dd7070Spatrick     // Inspect the initializer of the variable declaration which is
1000e5dd7070Spatrick     // being referenced prior to its initialization. We emit
1001e5dd7070Spatrick     // specialized diagnostics for self-initialization, and we
1002e5dd7070Spatrick     // specifically avoid warning about self references which take the
1003e5dd7070Spatrick     // form of:
1004e5dd7070Spatrick     //
1005e5dd7070Spatrick     //   int x = x;
1006e5dd7070Spatrick     //
1007e5dd7070Spatrick     // This is used to indicate to GCC that 'x' is intentionally left
1008e5dd7070Spatrick     // uninitialized. Proven code paths which access 'x' in
1009e5dd7070Spatrick     // an uninitialized state after this will still warn.
1010e5dd7070Spatrick     if (const Expr *Initializer = VD->getInit()) {
1011e5dd7070Spatrick       if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts())
1012e5dd7070Spatrick         return false;
1013e5dd7070Spatrick 
1014e5dd7070Spatrick       ContainsReference CR(S.Context, DRE);
1015e5dd7070Spatrick       CR.Visit(Initializer);
1016e5dd7070Spatrick       if (CR.doesContainReference()) {
1017e5dd7070Spatrick         S.Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
1018e5dd7070Spatrick             << VD->getDeclName() << VD->getLocation() << DRE->getSourceRange();
1019e5dd7070Spatrick         return true;
1020e5dd7070Spatrick       }
1021e5dd7070Spatrick     }
1022e5dd7070Spatrick 
1023e5dd7070Spatrick     DiagUninitUse(S, VD, Use, false);
1024e5dd7070Spatrick   } else {
1025e5dd7070Spatrick     const BlockExpr *BE = cast<BlockExpr>(Use.getUser());
1026e5dd7070Spatrick     if (VD->getType()->isBlockPointerType() && !VD->hasAttr<BlocksAttr>())
1027e5dd7070Spatrick       S.Diag(BE->getBeginLoc(),
1028e5dd7070Spatrick              diag::warn_uninit_byref_blockvar_captured_by_block)
1029e5dd7070Spatrick           << VD->getDeclName()
1030e5dd7070Spatrick           << VD->getType().getQualifiers().hasObjCLifetime();
1031e5dd7070Spatrick     else
1032e5dd7070Spatrick       DiagUninitUse(S, VD, Use, true);
1033e5dd7070Spatrick   }
1034e5dd7070Spatrick 
1035e5dd7070Spatrick   // Report where the variable was declared when the use wasn't within
1036e5dd7070Spatrick   // the initializer of that declaration & we didn't already suggest
1037e5dd7070Spatrick   // an initialization fixit.
1038e5dd7070Spatrick   if (!SuggestInitializationFixit(S, VD))
1039e5dd7070Spatrick     S.Diag(VD->getBeginLoc(), diag::note_var_declared_here)
1040e5dd7070Spatrick         << VD->getDeclName();
1041e5dd7070Spatrick 
1042e5dd7070Spatrick   return true;
1043e5dd7070Spatrick }
1044e5dd7070Spatrick 
1045e5dd7070Spatrick namespace {
1046e5dd7070Spatrick   class FallthroughMapper : public RecursiveASTVisitor<FallthroughMapper> {
1047e5dd7070Spatrick   public:
FallthroughMapper(Sema & S)1048e5dd7070Spatrick     FallthroughMapper(Sema &S)
1049e5dd7070Spatrick       : FoundSwitchStatements(false),
1050e5dd7070Spatrick         S(S) {
1051e5dd7070Spatrick     }
1052e5dd7070Spatrick 
foundSwitchStatements() const1053e5dd7070Spatrick     bool foundSwitchStatements() const { return FoundSwitchStatements; }
1054e5dd7070Spatrick 
markFallthroughVisited(const AttributedStmt * Stmt)1055e5dd7070Spatrick     void markFallthroughVisited(const AttributedStmt *Stmt) {
1056e5dd7070Spatrick       bool Found = FallthroughStmts.erase(Stmt);
1057e5dd7070Spatrick       assert(Found);
1058e5dd7070Spatrick       (void)Found;
1059e5dd7070Spatrick     }
1060e5dd7070Spatrick 
1061e5dd7070Spatrick     typedef llvm::SmallPtrSet<const AttributedStmt*, 8> AttrStmts;
1062e5dd7070Spatrick 
getFallthroughStmts() const1063e5dd7070Spatrick     const AttrStmts &getFallthroughStmts() const {
1064e5dd7070Spatrick       return FallthroughStmts;
1065e5dd7070Spatrick     }
1066e5dd7070Spatrick 
fillReachableBlocks(CFG * Cfg)1067e5dd7070Spatrick     void fillReachableBlocks(CFG *Cfg) {
1068e5dd7070Spatrick       assert(ReachableBlocks.empty() && "ReachableBlocks already filled");
1069e5dd7070Spatrick       std::deque<const CFGBlock *> BlockQueue;
1070e5dd7070Spatrick 
1071e5dd7070Spatrick       ReachableBlocks.insert(&Cfg->getEntry());
1072e5dd7070Spatrick       BlockQueue.push_back(&Cfg->getEntry());
1073e5dd7070Spatrick       // Mark all case blocks reachable to avoid problems with switching on
1074e5dd7070Spatrick       // constants, covered enums, etc.
1075e5dd7070Spatrick       // These blocks can contain fall-through annotations, and we don't want to
1076e5dd7070Spatrick       // issue a warn_fallthrough_attr_unreachable for them.
1077e5dd7070Spatrick       for (const auto *B : *Cfg) {
1078e5dd7070Spatrick         const Stmt *L = B->getLabel();
1079e5dd7070Spatrick         if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B).second)
1080e5dd7070Spatrick           BlockQueue.push_back(B);
1081e5dd7070Spatrick       }
1082e5dd7070Spatrick 
1083e5dd7070Spatrick       while (!BlockQueue.empty()) {
1084e5dd7070Spatrick         const CFGBlock *P = BlockQueue.front();
1085e5dd7070Spatrick         BlockQueue.pop_front();
1086*12c85518Srobert         for (const CFGBlock *B : P->succs()) {
1087*12c85518Srobert           if (B && ReachableBlocks.insert(B).second)
1088*12c85518Srobert             BlockQueue.push_back(B);
1089e5dd7070Spatrick         }
1090e5dd7070Spatrick       }
1091e5dd7070Spatrick     }
1092e5dd7070Spatrick 
checkFallThroughIntoBlock(const CFGBlock & B,int & AnnotatedCnt,bool IsTemplateInstantiation)1093e5dd7070Spatrick     bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt,
1094e5dd7070Spatrick                                    bool IsTemplateInstantiation) {
1095e5dd7070Spatrick       assert(!ReachableBlocks.empty() && "ReachableBlocks empty");
1096e5dd7070Spatrick 
1097e5dd7070Spatrick       int UnannotatedCnt = 0;
1098e5dd7070Spatrick       AnnotatedCnt = 0;
1099e5dd7070Spatrick 
1100e5dd7070Spatrick       std::deque<const CFGBlock*> BlockQueue(B.pred_begin(), B.pred_end());
1101e5dd7070Spatrick       while (!BlockQueue.empty()) {
1102e5dd7070Spatrick         const CFGBlock *P = BlockQueue.front();
1103e5dd7070Spatrick         BlockQueue.pop_front();
1104e5dd7070Spatrick         if (!P) continue;
1105e5dd7070Spatrick 
1106e5dd7070Spatrick         const Stmt *Term = P->getTerminatorStmt();
1107e5dd7070Spatrick         if (Term && isa<SwitchStmt>(Term))
1108e5dd7070Spatrick           continue; // Switch statement, good.
1109e5dd7070Spatrick 
1110e5dd7070Spatrick         const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->getLabel());
1111e5dd7070Spatrick         if (SW && SW->getSubStmt() == B.getLabel() && P->begin() == P->end())
1112e5dd7070Spatrick           continue; // Previous case label has no statements, good.
1113e5dd7070Spatrick 
1114e5dd7070Spatrick         const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->getLabel());
1115e5dd7070Spatrick         if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end())
1116e5dd7070Spatrick           continue; // Case label is preceded with a normal label, good.
1117e5dd7070Spatrick 
1118e5dd7070Spatrick         if (!ReachableBlocks.count(P)) {
1119*12c85518Srobert           for (const CFGElement &Elem : llvm::reverse(*P)) {
1120*12c85518Srobert             if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) {
1121e5dd7070Spatrick             if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
1122e5dd7070Spatrick               // Don't issue a warning for an unreachable fallthrough
1123e5dd7070Spatrick               // attribute in template instantiations as it may not be
1124e5dd7070Spatrick               // unreachable in all instantiations of the template.
1125e5dd7070Spatrick               if (!IsTemplateInstantiation)
1126e5dd7070Spatrick                 S.Diag(AS->getBeginLoc(),
1127*12c85518Srobert                        diag::warn_unreachable_fallthrough_attr);
1128e5dd7070Spatrick               markFallthroughVisited(AS);
1129e5dd7070Spatrick               ++AnnotatedCnt;
1130e5dd7070Spatrick               break;
1131e5dd7070Spatrick             }
1132e5dd7070Spatrick             // Don't care about other unreachable statements.
1133e5dd7070Spatrick             }
1134e5dd7070Spatrick           }
1135e5dd7070Spatrick           // If there are no unreachable statements, this may be a special
1136e5dd7070Spatrick           // case in CFG:
1137e5dd7070Spatrick           // case X: {
1138e5dd7070Spatrick           //    A a;  // A has a destructor.
1139e5dd7070Spatrick           //    break;
1140e5dd7070Spatrick           // }
1141e5dd7070Spatrick           // // <<<< This place is represented by a 'hanging' CFG block.
1142e5dd7070Spatrick           // case Y:
1143e5dd7070Spatrick           continue;
1144e5dd7070Spatrick         }
1145e5dd7070Spatrick 
1146e5dd7070Spatrick         const Stmt *LastStmt = getLastStmt(*P);
1147e5dd7070Spatrick         if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {
1148e5dd7070Spatrick           markFallthroughVisited(AS);
1149e5dd7070Spatrick           ++AnnotatedCnt;
1150e5dd7070Spatrick           continue; // Fallthrough annotation, good.
1151e5dd7070Spatrick         }
1152e5dd7070Spatrick 
1153e5dd7070Spatrick         if (!LastStmt) { // This block contains no executable statements.
1154e5dd7070Spatrick           // Traverse its predecessors.
1155e5dd7070Spatrick           std::copy(P->pred_begin(), P->pred_end(),
1156e5dd7070Spatrick                     std::back_inserter(BlockQueue));
1157e5dd7070Spatrick           continue;
1158e5dd7070Spatrick         }
1159e5dd7070Spatrick 
1160e5dd7070Spatrick         ++UnannotatedCnt;
1161e5dd7070Spatrick       }
1162e5dd7070Spatrick       return !!UnannotatedCnt;
1163e5dd7070Spatrick     }
1164e5dd7070Spatrick 
1165e5dd7070Spatrick     // RecursiveASTVisitor setup.
shouldWalkTypesOfTypeLocs() const1166e5dd7070Spatrick     bool shouldWalkTypesOfTypeLocs() const { return false; }
1167e5dd7070Spatrick 
VisitAttributedStmt(AttributedStmt * S)1168e5dd7070Spatrick     bool VisitAttributedStmt(AttributedStmt *S) {
1169e5dd7070Spatrick       if (asFallThroughAttr(S))
1170e5dd7070Spatrick         FallthroughStmts.insert(S);
1171e5dd7070Spatrick       return true;
1172e5dd7070Spatrick     }
1173e5dd7070Spatrick 
VisitSwitchStmt(SwitchStmt * S)1174e5dd7070Spatrick     bool VisitSwitchStmt(SwitchStmt *S) {
1175e5dd7070Spatrick       FoundSwitchStatements = true;
1176e5dd7070Spatrick       return true;
1177e5dd7070Spatrick     }
1178e5dd7070Spatrick 
1179e5dd7070Spatrick     // We don't want to traverse local type declarations. We analyze their
1180e5dd7070Spatrick     // methods separately.
TraverseDecl(Decl * D)1181e5dd7070Spatrick     bool TraverseDecl(Decl *D) { return true; }
1182e5dd7070Spatrick 
1183e5dd7070Spatrick     // We analyze lambda bodies separately. Skip them here.
TraverseLambdaExpr(LambdaExpr * LE)1184e5dd7070Spatrick     bool TraverseLambdaExpr(LambdaExpr *LE) {
1185e5dd7070Spatrick       // Traverse the captures, but not the body.
1186e5dd7070Spatrick       for (const auto C : zip(LE->captures(), LE->capture_inits()))
1187e5dd7070Spatrick         TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C));
1188e5dd7070Spatrick       return true;
1189e5dd7070Spatrick     }
1190e5dd7070Spatrick 
1191e5dd7070Spatrick   private:
1192e5dd7070Spatrick 
asFallThroughAttr(const Stmt * S)1193e5dd7070Spatrick     static const AttributedStmt *asFallThroughAttr(const Stmt *S) {
1194e5dd7070Spatrick       if (const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
1195e5dd7070Spatrick         if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs()))
1196e5dd7070Spatrick           return AS;
1197e5dd7070Spatrick       }
1198e5dd7070Spatrick       return nullptr;
1199e5dd7070Spatrick     }
1200e5dd7070Spatrick 
getLastStmt(const CFGBlock & B)1201e5dd7070Spatrick     static const Stmt *getLastStmt(const CFGBlock &B) {
1202e5dd7070Spatrick       if (const Stmt *Term = B.getTerminatorStmt())
1203e5dd7070Spatrick         return Term;
1204*12c85518Srobert       for (const CFGElement &Elem : llvm::reverse(B))
1205*12c85518Srobert         if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
1206e5dd7070Spatrick           return CS->getStmt();
1207e5dd7070Spatrick       // Workaround to detect a statement thrown out by CFGBuilder:
1208e5dd7070Spatrick       //   case X: {} case Y:
1209e5dd7070Spatrick       //   case X: ; case Y:
1210e5dd7070Spatrick       if (const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.getLabel()))
1211e5dd7070Spatrick         if (!isa<SwitchCase>(SW->getSubStmt()))
1212e5dd7070Spatrick           return SW->getSubStmt();
1213e5dd7070Spatrick 
1214e5dd7070Spatrick       return nullptr;
1215e5dd7070Spatrick     }
1216e5dd7070Spatrick 
1217e5dd7070Spatrick     bool FoundSwitchStatements;
1218e5dd7070Spatrick     AttrStmts FallthroughStmts;
1219e5dd7070Spatrick     Sema &S;
1220e5dd7070Spatrick     llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
1221e5dd7070Spatrick   };
1222e5dd7070Spatrick } // anonymous namespace
1223e5dd7070Spatrick 
getFallthroughAttrSpelling(Preprocessor & PP,SourceLocation Loc)1224e5dd7070Spatrick static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
1225e5dd7070Spatrick                                             SourceLocation Loc) {
1226e5dd7070Spatrick   TokenValue FallthroughTokens[] = {
1227e5dd7070Spatrick     tok::l_square, tok::l_square,
1228e5dd7070Spatrick     PP.getIdentifierInfo("fallthrough"),
1229e5dd7070Spatrick     tok::r_square, tok::r_square
1230e5dd7070Spatrick   };
1231e5dd7070Spatrick 
1232e5dd7070Spatrick   TokenValue ClangFallthroughTokens[] = {
1233e5dd7070Spatrick     tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"),
1234e5dd7070Spatrick     tok::coloncolon, PP.getIdentifierInfo("fallthrough"),
1235e5dd7070Spatrick     tok::r_square, tok::r_square
1236e5dd7070Spatrick   };
1237e5dd7070Spatrick 
1238e5dd7070Spatrick   bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17 && !PP.getLangOpts().C2x;
1239e5dd7070Spatrick 
1240e5dd7070Spatrick   StringRef MacroName;
1241e5dd7070Spatrick   if (PreferClangAttr)
1242e5dd7070Spatrick     MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens);
1243e5dd7070Spatrick   if (MacroName.empty())
1244e5dd7070Spatrick     MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens);
1245e5dd7070Spatrick   if (MacroName.empty() && !PreferClangAttr)
1246e5dd7070Spatrick     MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens);
1247e5dd7070Spatrick   if (MacroName.empty()) {
1248e5dd7070Spatrick     if (!PreferClangAttr)
1249e5dd7070Spatrick       MacroName = "[[fallthrough]]";
1250e5dd7070Spatrick     else if (PP.getLangOpts().CPlusPlus)
1251e5dd7070Spatrick       MacroName = "[[clang::fallthrough]]";
1252e5dd7070Spatrick     else
1253e5dd7070Spatrick       MacroName = "__attribute__((fallthrough))";
1254e5dd7070Spatrick   }
1255e5dd7070Spatrick   return MacroName;
1256e5dd7070Spatrick }
1257e5dd7070Spatrick 
DiagnoseSwitchLabelsFallthrough(Sema & S,AnalysisDeclContext & AC,bool PerFunction)1258e5dd7070Spatrick static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
1259e5dd7070Spatrick                                             bool PerFunction) {
1260e5dd7070Spatrick   FallthroughMapper FM(S);
1261e5dd7070Spatrick   FM.TraverseStmt(AC.getBody());
1262e5dd7070Spatrick 
1263e5dd7070Spatrick   if (!FM.foundSwitchStatements())
1264e5dd7070Spatrick     return;
1265e5dd7070Spatrick 
1266e5dd7070Spatrick   if (PerFunction && FM.getFallthroughStmts().empty())
1267e5dd7070Spatrick     return;
1268e5dd7070Spatrick 
1269e5dd7070Spatrick   CFG *Cfg = AC.getCFG();
1270e5dd7070Spatrick 
1271e5dd7070Spatrick   if (!Cfg)
1272e5dd7070Spatrick     return;
1273e5dd7070Spatrick 
1274e5dd7070Spatrick   FM.fillReachableBlocks(Cfg);
1275e5dd7070Spatrick 
1276e5dd7070Spatrick   for (const CFGBlock *B : llvm::reverse(*Cfg)) {
1277e5dd7070Spatrick     const Stmt *Label = B->getLabel();
1278e5dd7070Spatrick 
1279*12c85518Srobert     if (!isa_and_nonnull<SwitchCase>(Label))
1280e5dd7070Spatrick       continue;
1281e5dd7070Spatrick 
1282e5dd7070Spatrick     int AnnotatedCnt;
1283e5dd7070Spatrick 
1284e5dd7070Spatrick     bool IsTemplateInstantiation = false;
1285e5dd7070Spatrick     if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(AC.getDecl()))
1286e5dd7070Spatrick       IsTemplateInstantiation = Function->isTemplateInstantiation();
1287e5dd7070Spatrick     if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,
1288e5dd7070Spatrick                                       IsTemplateInstantiation))
1289e5dd7070Spatrick       continue;
1290e5dd7070Spatrick 
1291e5dd7070Spatrick     S.Diag(Label->getBeginLoc(),
1292e5dd7070Spatrick            PerFunction ? diag::warn_unannotated_fallthrough_per_function
1293e5dd7070Spatrick                        : diag::warn_unannotated_fallthrough);
1294e5dd7070Spatrick 
1295e5dd7070Spatrick     if (!AnnotatedCnt) {
1296e5dd7070Spatrick       SourceLocation L = Label->getBeginLoc();
1297e5dd7070Spatrick       if (L.isMacroID())
1298e5dd7070Spatrick         continue;
1299e5dd7070Spatrick 
1300e5dd7070Spatrick       const Stmt *Term = B->getTerminatorStmt();
1301e5dd7070Spatrick       // Skip empty cases.
1302e5dd7070Spatrick       while (B->empty() && !Term && B->succ_size() == 1) {
1303e5dd7070Spatrick         B = *B->succ_begin();
1304e5dd7070Spatrick         Term = B->getTerminatorStmt();
1305e5dd7070Spatrick       }
1306e5dd7070Spatrick       if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
1307e5dd7070Spatrick         Preprocessor &PP = S.getPreprocessor();
1308e5dd7070Spatrick         StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L);
1309e5dd7070Spatrick         SmallString<64> TextToInsert(AnnotationSpelling);
1310e5dd7070Spatrick         TextToInsert += "; ";
1311e5dd7070Spatrick         S.Diag(L, diag::note_insert_fallthrough_fixit)
1312e5dd7070Spatrick             << AnnotationSpelling
1313e5dd7070Spatrick             << FixItHint::CreateInsertion(L, TextToInsert);
1314e5dd7070Spatrick       }
1315e5dd7070Spatrick       S.Diag(L, diag::note_insert_break_fixit)
1316e5dd7070Spatrick           << FixItHint::CreateInsertion(L, "break; ");
1317e5dd7070Spatrick     }
1318e5dd7070Spatrick   }
1319e5dd7070Spatrick 
1320e5dd7070Spatrick   for (const auto *F : FM.getFallthroughStmts())
1321e5dd7070Spatrick     S.Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement);
1322e5dd7070Spatrick }
1323e5dd7070Spatrick 
isInLoop(const ASTContext & Ctx,const ParentMap & PM,const Stmt * S)1324e5dd7070Spatrick static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM,
1325e5dd7070Spatrick                      const Stmt *S) {
1326e5dd7070Spatrick   assert(S);
1327e5dd7070Spatrick 
1328e5dd7070Spatrick   do {
1329e5dd7070Spatrick     switch (S->getStmtClass()) {
1330e5dd7070Spatrick     case Stmt::ForStmtClass:
1331e5dd7070Spatrick     case Stmt::WhileStmtClass:
1332e5dd7070Spatrick     case Stmt::CXXForRangeStmtClass:
1333e5dd7070Spatrick     case Stmt::ObjCForCollectionStmtClass:
1334e5dd7070Spatrick       return true;
1335e5dd7070Spatrick     case Stmt::DoStmtClass: {
1336e5dd7070Spatrick       Expr::EvalResult Result;
1337e5dd7070Spatrick       if (!cast<DoStmt>(S)->getCond()->EvaluateAsInt(Result, Ctx))
1338e5dd7070Spatrick         return true;
1339e5dd7070Spatrick       return Result.Val.getInt().getBoolValue();
1340e5dd7070Spatrick     }
1341e5dd7070Spatrick     default:
1342e5dd7070Spatrick       break;
1343e5dd7070Spatrick     }
1344e5dd7070Spatrick   } while ((S = PM.getParent(S)));
1345e5dd7070Spatrick 
1346e5dd7070Spatrick   return false;
1347e5dd7070Spatrick }
1348e5dd7070Spatrick 
diagnoseRepeatedUseOfWeak(Sema & S,const sema::FunctionScopeInfo * CurFn,const Decl * D,const ParentMap & PM)1349e5dd7070Spatrick static void diagnoseRepeatedUseOfWeak(Sema &S,
1350e5dd7070Spatrick                                       const sema::FunctionScopeInfo *CurFn,
1351e5dd7070Spatrick                                       const Decl *D,
1352e5dd7070Spatrick                                       const ParentMap &PM) {
1353e5dd7070Spatrick   typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy;
1354e5dd7070Spatrick   typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap;
1355e5dd7070Spatrick   typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector;
1356e5dd7070Spatrick   typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
1357e5dd7070Spatrick   StmtUsesPair;
1358e5dd7070Spatrick 
1359e5dd7070Spatrick   ASTContext &Ctx = S.getASTContext();
1360e5dd7070Spatrick 
1361e5dd7070Spatrick   const WeakObjectUseMap &WeakMap = CurFn->getWeakObjectUses();
1362e5dd7070Spatrick 
1363e5dd7070Spatrick   // Extract all weak objects that are referenced more than once.
1364e5dd7070Spatrick   SmallVector<StmtUsesPair, 8> UsesByStmt;
1365e5dd7070Spatrick   for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end();
1366e5dd7070Spatrick        I != E; ++I) {
1367e5dd7070Spatrick     const WeakUseVector &Uses = I->second;
1368e5dd7070Spatrick 
1369e5dd7070Spatrick     // Find the first read of the weak object.
1370e5dd7070Spatrick     WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
1371e5dd7070Spatrick     for ( ; UI != UE; ++UI) {
1372e5dd7070Spatrick       if (UI->isUnsafe())
1373e5dd7070Spatrick         break;
1374e5dd7070Spatrick     }
1375e5dd7070Spatrick 
1376e5dd7070Spatrick     // If there were only writes to this object, don't warn.
1377e5dd7070Spatrick     if (UI == UE)
1378e5dd7070Spatrick       continue;
1379e5dd7070Spatrick 
1380e5dd7070Spatrick     // If there was only one read, followed by any number of writes, and the
1381e5dd7070Spatrick     // read is not within a loop, don't warn. Additionally, don't warn in a
1382e5dd7070Spatrick     // loop if the base object is a local variable -- local variables are often
1383e5dd7070Spatrick     // changed in loops.
1384e5dd7070Spatrick     if (UI == Uses.begin()) {
1385e5dd7070Spatrick       WeakUseVector::const_iterator UI2 = UI;
1386e5dd7070Spatrick       for (++UI2; UI2 != UE; ++UI2)
1387e5dd7070Spatrick         if (UI2->isUnsafe())
1388e5dd7070Spatrick           break;
1389e5dd7070Spatrick 
1390e5dd7070Spatrick       if (UI2 == UE) {
1391e5dd7070Spatrick         if (!isInLoop(Ctx, PM, UI->getUseExpr()))
1392e5dd7070Spatrick           continue;
1393e5dd7070Spatrick 
1394e5dd7070Spatrick         const WeakObjectProfileTy &Profile = I->first;
1395e5dd7070Spatrick         if (!Profile.isExactProfile())
1396e5dd7070Spatrick           continue;
1397e5dd7070Spatrick 
1398e5dd7070Spatrick         const NamedDecl *Base = Profile.getBase();
1399e5dd7070Spatrick         if (!Base)
1400e5dd7070Spatrick           Base = Profile.getProperty();
1401e5dd7070Spatrick         assert(Base && "A profile always has a base or property.");
1402e5dd7070Spatrick 
1403e5dd7070Spatrick         if (const VarDecl *BaseVar = dyn_cast<VarDecl>(Base))
1404e5dd7070Spatrick           if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(Base))
1405e5dd7070Spatrick             continue;
1406e5dd7070Spatrick       }
1407e5dd7070Spatrick     }
1408e5dd7070Spatrick 
1409e5dd7070Spatrick     UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
1410e5dd7070Spatrick   }
1411e5dd7070Spatrick 
1412e5dd7070Spatrick   if (UsesByStmt.empty())
1413e5dd7070Spatrick     return;
1414e5dd7070Spatrick 
1415e5dd7070Spatrick   // Sort by first use so that we emit the warnings in a deterministic order.
1416e5dd7070Spatrick   SourceManager &SM = S.getSourceManager();
1417e5dd7070Spatrick   llvm::sort(UsesByStmt,
1418e5dd7070Spatrick              [&SM](const StmtUsesPair &LHS, const StmtUsesPair &RHS) {
1419e5dd7070Spatrick                return SM.isBeforeInTranslationUnit(LHS.first->getBeginLoc(),
1420e5dd7070Spatrick                                                    RHS.first->getBeginLoc());
1421e5dd7070Spatrick              });
1422e5dd7070Spatrick 
1423e5dd7070Spatrick   // Classify the current code body for better warning text.
1424e5dd7070Spatrick   // This enum should stay in sync with the cases in
1425e5dd7070Spatrick   // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.
1426e5dd7070Spatrick   // FIXME: Should we use a common classification enum and the same set of
1427e5dd7070Spatrick   // possibilities all throughout Sema?
1428e5dd7070Spatrick   enum {
1429e5dd7070Spatrick     Function,
1430e5dd7070Spatrick     Method,
1431e5dd7070Spatrick     Block,
1432e5dd7070Spatrick     Lambda
1433e5dd7070Spatrick   } FunctionKind;
1434e5dd7070Spatrick 
1435e5dd7070Spatrick   if (isa<sema::BlockScopeInfo>(CurFn))
1436e5dd7070Spatrick     FunctionKind = Block;
1437e5dd7070Spatrick   else if (isa<sema::LambdaScopeInfo>(CurFn))
1438e5dd7070Spatrick     FunctionKind = Lambda;
1439e5dd7070Spatrick   else if (isa<ObjCMethodDecl>(D))
1440e5dd7070Spatrick     FunctionKind = Method;
1441e5dd7070Spatrick   else
1442e5dd7070Spatrick     FunctionKind = Function;
1443e5dd7070Spatrick 
1444e5dd7070Spatrick   // Iterate through the sorted problems and emit warnings for each.
1445e5dd7070Spatrick   for (const auto &P : UsesByStmt) {
1446e5dd7070Spatrick     const Stmt *FirstRead = P.first;
1447e5dd7070Spatrick     const WeakObjectProfileTy &Key = P.second->first;
1448e5dd7070Spatrick     const WeakUseVector &Uses = P.second->second;
1449e5dd7070Spatrick 
1450e5dd7070Spatrick     // For complicated expressions like 'a.b.c' and 'x.b.c', WeakObjectProfileTy
1451e5dd7070Spatrick     // may not contain enough information to determine that these are different
1452e5dd7070Spatrick     // properties. We can only be 100% sure of a repeated use in certain cases,
1453e5dd7070Spatrick     // and we adjust the diagnostic kind accordingly so that the less certain
1454e5dd7070Spatrick     // case can be turned off if it is too noisy.
1455e5dd7070Spatrick     unsigned DiagKind;
1456e5dd7070Spatrick     if (Key.isExactProfile())
1457e5dd7070Spatrick       DiagKind = diag::warn_arc_repeated_use_of_weak;
1458e5dd7070Spatrick     else
1459e5dd7070Spatrick       DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
1460e5dd7070Spatrick 
1461e5dd7070Spatrick     // Classify the weak object being accessed for better warning text.
1462e5dd7070Spatrick     // This enum should stay in sync with the cases in
1463e5dd7070Spatrick     // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.
1464e5dd7070Spatrick     enum {
1465e5dd7070Spatrick       Variable,
1466e5dd7070Spatrick       Property,
1467e5dd7070Spatrick       ImplicitProperty,
1468e5dd7070Spatrick       Ivar
1469e5dd7070Spatrick     } ObjectKind;
1470e5dd7070Spatrick 
1471e5dd7070Spatrick     const NamedDecl *KeyProp = Key.getProperty();
1472e5dd7070Spatrick     if (isa<VarDecl>(KeyProp))
1473e5dd7070Spatrick       ObjectKind = Variable;
1474e5dd7070Spatrick     else if (isa<ObjCPropertyDecl>(KeyProp))
1475e5dd7070Spatrick       ObjectKind = Property;
1476e5dd7070Spatrick     else if (isa<ObjCMethodDecl>(KeyProp))
1477e5dd7070Spatrick       ObjectKind = ImplicitProperty;
1478e5dd7070Spatrick     else if (isa<ObjCIvarDecl>(KeyProp))
1479e5dd7070Spatrick       ObjectKind = Ivar;
1480e5dd7070Spatrick     else
1481e5dd7070Spatrick       llvm_unreachable("Unexpected weak object kind!");
1482e5dd7070Spatrick 
1483e5dd7070Spatrick     // Do not warn about IBOutlet weak property receivers being set to null
1484e5dd7070Spatrick     // since they are typically only used from the main thread.
1485e5dd7070Spatrick     if (const ObjCPropertyDecl *Prop = dyn_cast<ObjCPropertyDecl>(KeyProp))
1486e5dd7070Spatrick       if (Prop->hasAttr<IBOutletAttr>())
1487e5dd7070Spatrick         continue;
1488e5dd7070Spatrick 
1489e5dd7070Spatrick     // Show the first time the object was read.
1490e5dd7070Spatrick     S.Diag(FirstRead->getBeginLoc(), DiagKind)
1491e5dd7070Spatrick         << int(ObjectKind) << KeyProp << int(FunctionKind)
1492e5dd7070Spatrick         << FirstRead->getSourceRange();
1493e5dd7070Spatrick 
1494e5dd7070Spatrick     // Print all the other accesses as notes.
1495e5dd7070Spatrick     for (const auto &Use : Uses) {
1496e5dd7070Spatrick       if (Use.getUseExpr() == FirstRead)
1497e5dd7070Spatrick         continue;
1498e5dd7070Spatrick       S.Diag(Use.getUseExpr()->getBeginLoc(),
1499e5dd7070Spatrick              diag::note_arc_weak_also_accessed_here)
1500e5dd7070Spatrick           << Use.getUseExpr()->getSourceRange();
1501e5dd7070Spatrick     }
1502e5dd7070Spatrick   }
1503e5dd7070Spatrick }
1504e5dd7070Spatrick 
1505a9ac8606Spatrick namespace clang {
1506a9ac8606Spatrick namespace {
1507a9ac8606Spatrick typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
1508a9ac8606Spatrick typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;
1509a9ac8606Spatrick typedef std::list<DelayedDiag> DiagList;
1510a9ac8606Spatrick 
1511a9ac8606Spatrick struct SortDiagBySourceLocation {
1512a9ac8606Spatrick   SourceManager &SM;
SortDiagBySourceLocationclang::__anon27fad7f20c11::SortDiagBySourceLocation1513a9ac8606Spatrick   SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {}
1514a9ac8606Spatrick 
operator ()clang::__anon27fad7f20c11::SortDiagBySourceLocation1515a9ac8606Spatrick   bool operator()(const DelayedDiag &left, const DelayedDiag &right) {
1516a9ac8606Spatrick     // Although this call will be slow, this is only called when outputting
1517a9ac8606Spatrick     // multiple warnings.
1518a9ac8606Spatrick     return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
1519a9ac8606Spatrick   }
1520a9ac8606Spatrick };
1521a9ac8606Spatrick } // anonymous namespace
1522a9ac8606Spatrick } // namespace clang
1523a9ac8606Spatrick 
1524e5dd7070Spatrick namespace {
1525e5dd7070Spatrick class UninitValsDiagReporter : public UninitVariablesHandler {
1526e5dd7070Spatrick   Sema &S;
1527e5dd7070Spatrick   typedef SmallVector<UninitUse, 2> UsesVec;
1528e5dd7070Spatrick   typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
1529e5dd7070Spatrick   // Prefer using MapVector to DenseMap, so that iteration order will be
1530e5dd7070Spatrick   // the same as insertion order. This is needed to obtain a deterministic
1531e5dd7070Spatrick   // order of diagnostics when calling flushDiagnostics().
1532e5dd7070Spatrick   typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
1533e5dd7070Spatrick   UsesMap uses;
1534ec727ea7Spatrick   UsesMap constRefUses;
1535e5dd7070Spatrick 
1536e5dd7070Spatrick public:
UninitValsDiagReporter(Sema & S)1537e5dd7070Spatrick   UninitValsDiagReporter(Sema &S) : S(S) {}
~UninitValsDiagReporter()1538e5dd7070Spatrick   ~UninitValsDiagReporter() override { flushDiagnostics(); }
1539e5dd7070Spatrick 
getUses(UsesMap & um,const VarDecl * vd)1540ec727ea7Spatrick   MappedType &getUses(UsesMap &um, const VarDecl *vd) {
1541ec727ea7Spatrick     MappedType &V = um[vd];
1542e5dd7070Spatrick     if (!V.getPointer())
1543e5dd7070Spatrick       V.setPointer(new UsesVec());
1544e5dd7070Spatrick     return V;
1545e5dd7070Spatrick   }
1546e5dd7070Spatrick 
handleUseOfUninitVariable(const VarDecl * vd,const UninitUse & use)1547e5dd7070Spatrick   void handleUseOfUninitVariable(const VarDecl *vd,
1548e5dd7070Spatrick                                  const UninitUse &use) override {
1549ec727ea7Spatrick     getUses(uses, vd).getPointer()->push_back(use);
1550ec727ea7Spatrick   }
1551ec727ea7Spatrick 
handleConstRefUseOfUninitVariable(const VarDecl * vd,const UninitUse & use)1552ec727ea7Spatrick   void handleConstRefUseOfUninitVariable(const VarDecl *vd,
1553ec727ea7Spatrick                                          const UninitUse &use) override {
1554ec727ea7Spatrick     getUses(constRefUses, vd).getPointer()->push_back(use);
1555e5dd7070Spatrick   }
1556e5dd7070Spatrick 
handleSelfInit(const VarDecl * vd)1557e5dd7070Spatrick   void handleSelfInit(const VarDecl *vd) override {
1558ec727ea7Spatrick     getUses(uses, vd).setInt(true);
1559ec727ea7Spatrick     getUses(constRefUses, vd).setInt(true);
1560e5dd7070Spatrick   }
1561e5dd7070Spatrick 
flushDiagnostics()1562e5dd7070Spatrick   void flushDiagnostics() {
1563e5dd7070Spatrick     for (const auto &P : uses) {
1564e5dd7070Spatrick       const VarDecl *vd = P.first;
1565e5dd7070Spatrick       const MappedType &V = P.second;
1566e5dd7070Spatrick 
1567e5dd7070Spatrick       UsesVec *vec = V.getPointer();
1568e5dd7070Spatrick       bool hasSelfInit = V.getInt();
1569e5dd7070Spatrick 
1570e5dd7070Spatrick       // Specially handle the case where we have uses of an uninitialized
1571e5dd7070Spatrick       // variable, but the root cause is an idiomatic self-init.  We want
1572e5dd7070Spatrick       // to report the diagnostic at the self-init since that is the root cause.
1573e5dd7070Spatrick       if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
1574e5dd7070Spatrick         DiagnoseUninitializedUse(S, vd,
1575e5dd7070Spatrick                                  UninitUse(vd->getInit()->IgnoreParenCasts(),
1576e5dd7070Spatrick                                            /* isAlwaysUninit */ true),
1577e5dd7070Spatrick                                  /* alwaysReportSelfInit */ true);
1578e5dd7070Spatrick       else {
1579e5dd7070Spatrick         // Sort the uses by their SourceLocations.  While not strictly
1580e5dd7070Spatrick         // guaranteed to produce them in line/column order, this will provide
1581e5dd7070Spatrick         // a stable ordering.
1582*12c85518Srobert         llvm::sort(*vec, [](const UninitUse &a, const UninitUse &b) {
1583e5dd7070Spatrick           // Prefer a more confident report over a less confident one.
1584e5dd7070Spatrick           if (a.getKind() != b.getKind())
1585e5dd7070Spatrick             return a.getKind() > b.getKind();
1586e5dd7070Spatrick           return a.getUser()->getBeginLoc() < b.getUser()->getBeginLoc();
1587e5dd7070Spatrick         });
1588e5dd7070Spatrick 
1589e5dd7070Spatrick         for (const auto &U : *vec) {
1590e5dd7070Spatrick           // If we have self-init, downgrade all uses to 'may be uninitialized'.
1591e5dd7070Spatrick           UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U;
1592e5dd7070Spatrick 
1593e5dd7070Spatrick           if (DiagnoseUninitializedUse(S, vd, Use))
1594e5dd7070Spatrick             // Skip further diagnostics for this variable. We try to warn only
1595e5dd7070Spatrick             // on the first point at which a variable is used uninitialized.
1596e5dd7070Spatrick             break;
1597e5dd7070Spatrick         }
1598e5dd7070Spatrick       }
1599e5dd7070Spatrick 
1600e5dd7070Spatrick       // Release the uses vector.
1601e5dd7070Spatrick       delete vec;
1602e5dd7070Spatrick     }
1603e5dd7070Spatrick 
1604e5dd7070Spatrick     uses.clear();
1605ec727ea7Spatrick 
1606ec727ea7Spatrick     // Flush all const reference uses diags.
1607ec727ea7Spatrick     for (const auto &P : constRefUses) {
1608ec727ea7Spatrick       const VarDecl *vd = P.first;
1609ec727ea7Spatrick       const MappedType &V = P.second;
1610ec727ea7Spatrick 
1611ec727ea7Spatrick       UsesVec *vec = V.getPointer();
1612ec727ea7Spatrick       bool hasSelfInit = V.getInt();
1613ec727ea7Spatrick 
1614ec727ea7Spatrick       if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
1615ec727ea7Spatrick         DiagnoseUninitializedUse(S, vd,
1616ec727ea7Spatrick                                  UninitUse(vd->getInit()->IgnoreParenCasts(),
1617ec727ea7Spatrick                                            /* isAlwaysUninit */ true),
1618ec727ea7Spatrick                                  /* alwaysReportSelfInit */ true);
1619ec727ea7Spatrick       else {
1620ec727ea7Spatrick         for (const auto &U : *vec) {
1621ec727ea7Spatrick           if (DiagnoseUninitializedConstRefUse(S, vd, U))
1622ec727ea7Spatrick             break;
1623ec727ea7Spatrick         }
1624ec727ea7Spatrick       }
1625ec727ea7Spatrick 
1626ec727ea7Spatrick       // Release the uses vector.
1627ec727ea7Spatrick       delete vec;
1628ec727ea7Spatrick     }
1629ec727ea7Spatrick 
1630ec727ea7Spatrick     constRefUses.clear();
1631e5dd7070Spatrick   }
1632e5dd7070Spatrick 
1633e5dd7070Spatrick private:
hasAlwaysUninitializedUse(const UsesVec * vec)1634e5dd7070Spatrick   static bool hasAlwaysUninitializedUse(const UsesVec* vec) {
1635*12c85518Srobert     return llvm::any_of(*vec, [](const UninitUse &U) {
1636e5dd7070Spatrick       return U.getKind() == UninitUse::Always ||
1637e5dd7070Spatrick              U.getKind() == UninitUse::AfterCall ||
1638e5dd7070Spatrick              U.getKind() == UninitUse::AfterDecl;
1639e5dd7070Spatrick     });
1640e5dd7070Spatrick   }
1641e5dd7070Spatrick };
1642e5dd7070Spatrick 
1643a9ac8606Spatrick /// Inter-procedural data for the called-once checker.
1644a9ac8606Spatrick class CalledOnceInterProceduralData {
1645a9ac8606Spatrick public:
1646a9ac8606Spatrick   // Add the delayed warning for the given block.
addDelayedWarning(const BlockDecl * Block,PartialDiagnosticAt && Warning)1647a9ac8606Spatrick   void addDelayedWarning(const BlockDecl *Block,
1648a9ac8606Spatrick                          PartialDiagnosticAt &&Warning) {
1649a9ac8606Spatrick     DelayedBlockWarnings[Block].emplace_back(std::move(Warning));
1650e5dd7070Spatrick   }
1651a9ac8606Spatrick   // Report all of the warnings we've gathered for the given block.
flushWarnings(const BlockDecl * Block,Sema & S)1652a9ac8606Spatrick   void flushWarnings(const BlockDecl *Block, Sema &S) {
1653a9ac8606Spatrick     for (const PartialDiagnosticAt &Delayed : DelayedBlockWarnings[Block])
1654a9ac8606Spatrick       S.Diag(Delayed.first, Delayed.second);
1655a9ac8606Spatrick 
1656a9ac8606Spatrick     discardWarnings(Block);
1657a9ac8606Spatrick   }
1658a9ac8606Spatrick   // Discard all of the warnings we've gathered for the given block.
discardWarnings(const BlockDecl * Block)1659a9ac8606Spatrick   void discardWarnings(const BlockDecl *Block) {
1660a9ac8606Spatrick     DelayedBlockWarnings.erase(Block);
1661a9ac8606Spatrick   }
1662a9ac8606Spatrick 
1663a9ac8606Spatrick private:
1664a9ac8606Spatrick   using DelayedDiagnostics = SmallVector<PartialDiagnosticAt, 2>;
1665a9ac8606Spatrick   llvm::DenseMap<const BlockDecl *, DelayedDiagnostics> DelayedBlockWarnings;
1666e5dd7070Spatrick };
1667a9ac8606Spatrick 
1668a9ac8606Spatrick class CalledOnceCheckReporter : public CalledOnceCheckHandler {
1669a9ac8606Spatrick public:
CalledOnceCheckReporter(Sema & S,CalledOnceInterProceduralData & Data)1670a9ac8606Spatrick   CalledOnceCheckReporter(Sema &S, CalledOnceInterProceduralData &Data)
1671a9ac8606Spatrick       : S(S), Data(Data) {}
handleDoubleCall(const ParmVarDecl * Parameter,const Expr * Call,const Expr * PrevCall,bool IsCompletionHandler,bool Poised)1672a9ac8606Spatrick   void handleDoubleCall(const ParmVarDecl *Parameter, const Expr *Call,
1673a9ac8606Spatrick                         const Expr *PrevCall, bool IsCompletionHandler,
1674a9ac8606Spatrick                         bool Poised) override {
1675a9ac8606Spatrick     auto DiagToReport = IsCompletionHandler
1676a9ac8606Spatrick                             ? diag::warn_completion_handler_called_twice
1677a9ac8606Spatrick                             : diag::warn_called_once_gets_called_twice;
1678a9ac8606Spatrick     S.Diag(Call->getBeginLoc(), DiagToReport) << Parameter;
1679a9ac8606Spatrick     S.Diag(PrevCall->getBeginLoc(), diag::note_called_once_gets_called_twice)
1680a9ac8606Spatrick         << Poised;
1681a9ac8606Spatrick   }
1682a9ac8606Spatrick 
handleNeverCalled(const ParmVarDecl * Parameter,bool IsCompletionHandler)1683a9ac8606Spatrick   void handleNeverCalled(const ParmVarDecl *Parameter,
1684a9ac8606Spatrick                          bool IsCompletionHandler) override {
1685a9ac8606Spatrick     auto DiagToReport = IsCompletionHandler
1686a9ac8606Spatrick                             ? diag::warn_completion_handler_never_called
1687a9ac8606Spatrick                             : diag::warn_called_once_never_called;
1688a9ac8606Spatrick     S.Diag(Parameter->getBeginLoc(), DiagToReport)
1689a9ac8606Spatrick         << Parameter << /* Captured */ false;
1690a9ac8606Spatrick   }
1691a9ac8606Spatrick 
handleNeverCalled(const ParmVarDecl * Parameter,const Decl * Function,const Stmt * Where,NeverCalledReason Reason,bool IsCalledDirectly,bool IsCompletionHandler)1692a9ac8606Spatrick   void handleNeverCalled(const ParmVarDecl *Parameter, const Decl *Function,
1693a9ac8606Spatrick                          const Stmt *Where, NeverCalledReason Reason,
1694a9ac8606Spatrick                          bool IsCalledDirectly,
1695a9ac8606Spatrick                          bool IsCompletionHandler) override {
1696a9ac8606Spatrick     auto DiagToReport = IsCompletionHandler
1697a9ac8606Spatrick                             ? diag::warn_completion_handler_never_called_when
1698a9ac8606Spatrick                             : diag::warn_called_once_never_called_when;
1699a9ac8606Spatrick     PartialDiagnosticAt Warning(Where->getBeginLoc(), S.PDiag(DiagToReport)
1700a9ac8606Spatrick                                                           << Parameter
1701a9ac8606Spatrick                                                           << IsCalledDirectly
1702a9ac8606Spatrick                                                           << (unsigned)Reason);
1703a9ac8606Spatrick 
1704a9ac8606Spatrick     if (const auto *Block = dyn_cast<BlockDecl>(Function)) {
1705a9ac8606Spatrick       // We shouldn't report these warnings on blocks immediately
1706a9ac8606Spatrick       Data.addDelayedWarning(Block, std::move(Warning));
1707a9ac8606Spatrick     } else {
1708a9ac8606Spatrick       S.Diag(Warning.first, Warning.second);
1709a9ac8606Spatrick     }
1710a9ac8606Spatrick   }
1711a9ac8606Spatrick 
handleCapturedNeverCalled(const ParmVarDecl * Parameter,const Decl * Where,bool IsCompletionHandler)1712a9ac8606Spatrick   void handleCapturedNeverCalled(const ParmVarDecl *Parameter,
1713a9ac8606Spatrick                                  const Decl *Where,
1714a9ac8606Spatrick                                  bool IsCompletionHandler) override {
1715a9ac8606Spatrick     auto DiagToReport = IsCompletionHandler
1716a9ac8606Spatrick                             ? diag::warn_completion_handler_never_called
1717a9ac8606Spatrick                             : diag::warn_called_once_never_called;
1718a9ac8606Spatrick     S.Diag(Where->getBeginLoc(), DiagToReport)
1719a9ac8606Spatrick         << Parameter << /* Captured */ true;
1720a9ac8606Spatrick   }
1721a9ac8606Spatrick 
1722a9ac8606Spatrick   void
handleBlockThatIsGuaranteedToBeCalledOnce(const BlockDecl * Block)1723a9ac8606Spatrick   handleBlockThatIsGuaranteedToBeCalledOnce(const BlockDecl *Block) override {
1724a9ac8606Spatrick     Data.flushWarnings(Block, S);
1725a9ac8606Spatrick   }
1726a9ac8606Spatrick 
handleBlockWithNoGuarantees(const BlockDecl * Block)1727a9ac8606Spatrick   void handleBlockWithNoGuarantees(const BlockDecl *Block) override {
1728a9ac8606Spatrick     Data.discardWarnings(Block);
1729a9ac8606Spatrick   }
1730a9ac8606Spatrick 
1731a9ac8606Spatrick private:
1732a9ac8606Spatrick   Sema &S;
1733a9ac8606Spatrick   CalledOnceInterProceduralData &Data;
1734a9ac8606Spatrick };
1735a9ac8606Spatrick 
1736a9ac8606Spatrick constexpr unsigned CalledOnceWarnings[] = {
1737a9ac8606Spatrick     diag::warn_called_once_never_called,
1738a9ac8606Spatrick     diag::warn_called_once_never_called_when,
1739a9ac8606Spatrick     diag::warn_called_once_gets_called_twice};
1740a9ac8606Spatrick 
1741a9ac8606Spatrick constexpr unsigned CompletionHandlerWarnings[]{
1742a9ac8606Spatrick     diag::warn_completion_handler_never_called,
1743a9ac8606Spatrick     diag::warn_completion_handler_never_called_when,
1744a9ac8606Spatrick     diag::warn_completion_handler_called_twice};
1745a9ac8606Spatrick 
shouldAnalyzeCalledOnceImpl(llvm::ArrayRef<unsigned> DiagIDs,const DiagnosticsEngine & Diags,SourceLocation At)1746a9ac8606Spatrick bool shouldAnalyzeCalledOnceImpl(llvm::ArrayRef<unsigned> DiagIDs,
1747a9ac8606Spatrick                                  const DiagnosticsEngine &Diags,
1748a9ac8606Spatrick                                  SourceLocation At) {
1749a9ac8606Spatrick   return llvm::any_of(DiagIDs, [&Diags, At](unsigned DiagID) {
1750a9ac8606Spatrick     return !Diags.isIgnored(DiagID, At);
1751a9ac8606Spatrick   });
1752a9ac8606Spatrick }
1753a9ac8606Spatrick 
shouldAnalyzeCalledOnceConventions(const DiagnosticsEngine & Diags,SourceLocation At)1754a9ac8606Spatrick bool shouldAnalyzeCalledOnceConventions(const DiagnosticsEngine &Diags,
1755a9ac8606Spatrick                                         SourceLocation At) {
1756a9ac8606Spatrick   return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);
1757a9ac8606Spatrick }
1758a9ac8606Spatrick 
shouldAnalyzeCalledOnceParameters(const DiagnosticsEngine & Diags,SourceLocation At)1759a9ac8606Spatrick bool shouldAnalyzeCalledOnceParameters(const DiagnosticsEngine &Diags,
1760a9ac8606Spatrick                                        SourceLocation At) {
1761a9ac8606Spatrick   return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||
1762a9ac8606Spatrick          shouldAnalyzeCalledOnceConventions(Diags, At);
1763a9ac8606Spatrick }
1764e5dd7070Spatrick } // anonymous namespace
1765e5dd7070Spatrick 
1766e5dd7070Spatrick //===----------------------------------------------------------------------===//
1767e5dd7070Spatrick // -Wthread-safety
1768e5dd7070Spatrick //===----------------------------------------------------------------------===//
1769e5dd7070Spatrick namespace clang {
1770e5dd7070Spatrick namespace threadSafety {
1771e5dd7070Spatrick namespace {
1772e5dd7070Spatrick class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
1773e5dd7070Spatrick   Sema &S;
1774e5dd7070Spatrick   DiagList Warnings;
1775e5dd7070Spatrick   SourceLocation FunLocation, FunEndLocation;
1776e5dd7070Spatrick 
1777e5dd7070Spatrick   const FunctionDecl *CurrentFunction;
1778e5dd7070Spatrick   bool Verbose;
1779e5dd7070Spatrick 
getNotes() const1780e5dd7070Spatrick   OptionalNotes getNotes() const {
1781e5dd7070Spatrick     if (Verbose && CurrentFunction) {
1782e5dd7070Spatrick       PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(),
1783e5dd7070Spatrick                                 S.PDiag(diag::note_thread_warning_in_fun)
1784e5dd7070Spatrick                                     << CurrentFunction);
1785e5dd7070Spatrick       return OptionalNotes(1, FNote);
1786e5dd7070Spatrick     }
1787e5dd7070Spatrick     return OptionalNotes();
1788e5dd7070Spatrick   }
1789e5dd7070Spatrick 
getNotes(const PartialDiagnosticAt & Note) const1790e5dd7070Spatrick   OptionalNotes getNotes(const PartialDiagnosticAt &Note) const {
1791e5dd7070Spatrick     OptionalNotes ONS(1, Note);
1792e5dd7070Spatrick     if (Verbose && CurrentFunction) {
1793e5dd7070Spatrick       PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(),
1794e5dd7070Spatrick                                 S.PDiag(diag::note_thread_warning_in_fun)
1795e5dd7070Spatrick                                     << CurrentFunction);
1796e5dd7070Spatrick       ONS.push_back(std::move(FNote));
1797e5dd7070Spatrick     }
1798e5dd7070Spatrick     return ONS;
1799e5dd7070Spatrick   }
1800e5dd7070Spatrick 
getNotes(const PartialDiagnosticAt & Note1,const PartialDiagnosticAt & Note2) const1801e5dd7070Spatrick   OptionalNotes getNotes(const PartialDiagnosticAt &Note1,
1802e5dd7070Spatrick                          const PartialDiagnosticAt &Note2) const {
1803e5dd7070Spatrick     OptionalNotes ONS;
1804e5dd7070Spatrick     ONS.push_back(Note1);
1805e5dd7070Spatrick     ONS.push_back(Note2);
1806e5dd7070Spatrick     if (Verbose && CurrentFunction) {
1807e5dd7070Spatrick       PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(),
1808e5dd7070Spatrick                                 S.PDiag(diag::note_thread_warning_in_fun)
1809e5dd7070Spatrick                                     << CurrentFunction);
1810e5dd7070Spatrick       ONS.push_back(std::move(FNote));
1811e5dd7070Spatrick     }
1812e5dd7070Spatrick     return ONS;
1813e5dd7070Spatrick   }
1814e5dd7070Spatrick 
makeLockedHereNote(SourceLocation LocLocked,StringRef Kind)1815e5dd7070Spatrick   OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) {
1816e5dd7070Spatrick     return LocLocked.isValid()
1817e5dd7070Spatrick                ? getNotes(PartialDiagnosticAt(
1818e5dd7070Spatrick                      LocLocked, S.PDiag(diag::note_locked_here) << Kind))
1819e5dd7070Spatrick                : getNotes();
1820e5dd7070Spatrick   }
1821e5dd7070Spatrick 
makeUnlockedHereNote(SourceLocation LocUnlocked,StringRef Kind)1822ec727ea7Spatrick   OptionalNotes makeUnlockedHereNote(SourceLocation LocUnlocked,
1823ec727ea7Spatrick                                      StringRef Kind) {
1824ec727ea7Spatrick     return LocUnlocked.isValid()
1825ec727ea7Spatrick                ? getNotes(PartialDiagnosticAt(
1826ec727ea7Spatrick                      LocUnlocked, S.PDiag(diag::note_unlocked_here) << Kind))
1827ec727ea7Spatrick                : getNotes();
1828ec727ea7Spatrick   }
1829ec727ea7Spatrick 
1830e5dd7070Spatrick  public:
ThreadSafetyReporter(Sema & S,SourceLocation FL,SourceLocation FEL)1831e5dd7070Spatrick   ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
1832e5dd7070Spatrick     : S(S), FunLocation(FL), FunEndLocation(FEL),
1833e5dd7070Spatrick       CurrentFunction(nullptr), Verbose(false) {}
1834e5dd7070Spatrick 
setVerbose(bool b)1835e5dd7070Spatrick   void setVerbose(bool b) { Verbose = b; }
1836e5dd7070Spatrick 
1837e5dd7070Spatrick   /// Emit all buffered diagnostics in order of sourcelocation.
1838e5dd7070Spatrick   /// We need to output diagnostics produced while iterating through
1839e5dd7070Spatrick   /// the lockset in deterministic order, so this function orders diagnostics
1840e5dd7070Spatrick   /// and outputs them.
emitDiagnostics()1841e5dd7070Spatrick   void emitDiagnostics() {
1842e5dd7070Spatrick     Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
1843e5dd7070Spatrick     for (const auto &Diag : Warnings) {
1844e5dd7070Spatrick       S.Diag(Diag.first.first, Diag.first.second);
1845e5dd7070Spatrick       for (const auto &Note : Diag.second)
1846e5dd7070Spatrick         S.Diag(Note.first, Note.second);
1847e5dd7070Spatrick     }
1848e5dd7070Spatrick   }
1849e5dd7070Spatrick 
handleInvalidLockExp(SourceLocation Loc)1850*12c85518Srobert   void handleInvalidLockExp(SourceLocation Loc) override {
1851e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_cannot_resolve_lock)
1852e5dd7070Spatrick                                          << Loc);
1853e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning), getNotes());
1854e5dd7070Spatrick   }
1855e5dd7070Spatrick 
handleUnmatchedUnlock(StringRef Kind,Name LockName,SourceLocation Loc,SourceLocation LocPreviousUnlock)1856ec727ea7Spatrick   void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc,
1857ec727ea7Spatrick                              SourceLocation LocPreviousUnlock) override {
1858e5dd7070Spatrick     if (Loc.isInvalid())
1859e5dd7070Spatrick       Loc = FunLocation;
1860e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_but_no_lock)
1861e5dd7070Spatrick                                          << Kind << LockName);
1862ec727ea7Spatrick     Warnings.emplace_back(std::move(Warning),
1863ec727ea7Spatrick                           makeUnlockedHereNote(LocPreviousUnlock, Kind));
1864e5dd7070Spatrick   }
1865e5dd7070Spatrick 
handleIncorrectUnlockKind(StringRef Kind,Name LockName,LockKind Expected,LockKind Received,SourceLocation LocLocked,SourceLocation LocUnlock)1866e5dd7070Spatrick   void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
1867e5dd7070Spatrick                                  LockKind Expected, LockKind Received,
1868e5dd7070Spatrick                                  SourceLocation LocLocked,
1869e5dd7070Spatrick                                  SourceLocation LocUnlock) override {
1870e5dd7070Spatrick     if (LocUnlock.isInvalid())
1871e5dd7070Spatrick       LocUnlock = FunLocation;
1872e5dd7070Spatrick     PartialDiagnosticAt Warning(
1873e5dd7070Spatrick         LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch)
1874e5dd7070Spatrick                        << Kind << LockName << Received << Expected);
1875e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning),
1876e5dd7070Spatrick                           makeLockedHereNote(LocLocked, Kind));
1877e5dd7070Spatrick   }
1878e5dd7070Spatrick 
handleDoubleLock(StringRef Kind,Name LockName,SourceLocation LocLocked,SourceLocation LocDoubleLock)1879e5dd7070Spatrick   void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked,
1880e5dd7070Spatrick                         SourceLocation LocDoubleLock) override {
1881e5dd7070Spatrick     if (LocDoubleLock.isInvalid())
1882e5dd7070Spatrick       LocDoubleLock = FunLocation;
1883e5dd7070Spatrick     PartialDiagnosticAt Warning(LocDoubleLock, S.PDiag(diag::warn_double_lock)
1884e5dd7070Spatrick                                                    << Kind << LockName);
1885e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning),
1886e5dd7070Spatrick                           makeLockedHereNote(LocLocked, Kind));
1887e5dd7070Spatrick   }
1888e5dd7070Spatrick 
handleMutexHeldEndOfScope(StringRef Kind,Name LockName,SourceLocation LocLocked,SourceLocation LocEndOfScope,LockErrorKind LEK)1889e5dd7070Spatrick   void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
1890e5dd7070Spatrick                                  SourceLocation LocLocked,
1891e5dd7070Spatrick                                  SourceLocation LocEndOfScope,
1892e5dd7070Spatrick                                  LockErrorKind LEK) override {
1893e5dd7070Spatrick     unsigned DiagID = 0;
1894e5dd7070Spatrick     switch (LEK) {
1895e5dd7070Spatrick       case LEK_LockedSomePredecessors:
1896e5dd7070Spatrick         DiagID = diag::warn_lock_some_predecessors;
1897e5dd7070Spatrick         break;
1898e5dd7070Spatrick       case LEK_LockedSomeLoopIterations:
1899e5dd7070Spatrick         DiagID = diag::warn_expecting_lock_held_on_loop;
1900e5dd7070Spatrick         break;
1901e5dd7070Spatrick       case LEK_LockedAtEndOfFunction:
1902e5dd7070Spatrick         DiagID = diag::warn_no_unlock;
1903e5dd7070Spatrick         break;
1904e5dd7070Spatrick       case LEK_NotLockedAtEndOfFunction:
1905e5dd7070Spatrick         DiagID = diag::warn_expecting_locked;
1906e5dd7070Spatrick         break;
1907e5dd7070Spatrick     }
1908e5dd7070Spatrick     if (LocEndOfScope.isInvalid())
1909e5dd7070Spatrick       LocEndOfScope = FunEndLocation;
1910e5dd7070Spatrick 
1911e5dd7070Spatrick     PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << Kind
1912e5dd7070Spatrick                                                                << LockName);
1913e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning),
1914e5dd7070Spatrick                           makeLockedHereNote(LocLocked, Kind));
1915e5dd7070Spatrick   }
1916e5dd7070Spatrick 
handleExclusiveAndShared(StringRef Kind,Name LockName,SourceLocation Loc1,SourceLocation Loc2)1917e5dd7070Spatrick   void handleExclusiveAndShared(StringRef Kind, Name LockName,
1918e5dd7070Spatrick                                 SourceLocation Loc1,
1919e5dd7070Spatrick                                 SourceLocation Loc2) override {
1920e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc1,
1921e5dd7070Spatrick                                 S.PDiag(diag::warn_lock_exclusive_and_shared)
1922e5dd7070Spatrick                                     << Kind << LockName);
1923e5dd7070Spatrick     PartialDiagnosticAt Note(Loc2, S.PDiag(diag::note_lock_exclusive_and_shared)
1924e5dd7070Spatrick                                        << Kind << LockName);
1925e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning), getNotes(Note));
1926e5dd7070Spatrick   }
1927e5dd7070Spatrick 
handleNoMutexHeld(const NamedDecl * D,ProtectedOperationKind POK,AccessKind AK,SourceLocation Loc)1928*12c85518Srobert   void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK,
1929*12c85518Srobert                          AccessKind AK, SourceLocation Loc) override {
1930e5dd7070Spatrick     assert((POK == POK_VarAccess || POK == POK_VarDereference) &&
1931e5dd7070Spatrick            "Only works for variables");
1932e5dd7070Spatrick     unsigned DiagID = POK == POK_VarAccess?
1933e5dd7070Spatrick                         diag::warn_variable_requires_any_lock:
1934e5dd7070Spatrick                         diag::warn_var_deref_requires_any_lock;
1935e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
1936e5dd7070Spatrick       << D << getLockKindFromAccessKind(AK));
1937e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning), getNotes());
1938e5dd7070Spatrick   }
1939e5dd7070Spatrick 
handleMutexNotHeld(StringRef Kind,const NamedDecl * D,ProtectedOperationKind POK,Name LockName,LockKind LK,SourceLocation Loc,Name * PossibleMatch)1940e5dd7070Spatrick   void handleMutexNotHeld(StringRef Kind, const NamedDecl *D,
1941e5dd7070Spatrick                           ProtectedOperationKind POK, Name LockName,
1942e5dd7070Spatrick                           LockKind LK, SourceLocation Loc,
1943e5dd7070Spatrick                           Name *PossibleMatch) override {
1944e5dd7070Spatrick     unsigned DiagID = 0;
1945e5dd7070Spatrick     if (PossibleMatch) {
1946e5dd7070Spatrick       switch (POK) {
1947e5dd7070Spatrick         case POK_VarAccess:
1948e5dd7070Spatrick           DiagID = diag::warn_variable_requires_lock_precise;
1949e5dd7070Spatrick           break;
1950e5dd7070Spatrick         case POK_VarDereference:
1951e5dd7070Spatrick           DiagID = diag::warn_var_deref_requires_lock_precise;
1952e5dd7070Spatrick           break;
1953e5dd7070Spatrick         case POK_FunctionCall:
1954e5dd7070Spatrick           DiagID = diag::warn_fun_requires_lock_precise;
1955e5dd7070Spatrick           break;
1956e5dd7070Spatrick         case POK_PassByRef:
1957e5dd7070Spatrick           DiagID = diag::warn_guarded_pass_by_reference;
1958e5dd7070Spatrick           break;
1959e5dd7070Spatrick         case POK_PtPassByRef:
1960e5dd7070Spatrick           DiagID = diag::warn_pt_guarded_pass_by_reference;
1961e5dd7070Spatrick           break;
1962e5dd7070Spatrick       }
1963e5dd7070Spatrick       PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind
1964e5dd7070Spatrick                                                        << D
1965e5dd7070Spatrick                                                        << LockName << LK);
1966e5dd7070Spatrick       PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match)
1967e5dd7070Spatrick                                         << *PossibleMatch);
1968e5dd7070Spatrick       if (Verbose && POK == POK_VarAccess) {
1969e5dd7070Spatrick         PartialDiagnosticAt VNote(D->getLocation(),
1970e5dd7070Spatrick                                   S.PDiag(diag::note_guarded_by_declared_here)
1971a9ac8606Spatrick                                       << D->getDeclName());
1972e5dd7070Spatrick         Warnings.emplace_back(std::move(Warning), getNotes(Note, VNote));
1973e5dd7070Spatrick       } else
1974e5dd7070Spatrick         Warnings.emplace_back(std::move(Warning), getNotes(Note));
1975e5dd7070Spatrick     } else {
1976e5dd7070Spatrick       switch (POK) {
1977e5dd7070Spatrick         case POK_VarAccess:
1978e5dd7070Spatrick           DiagID = diag::warn_variable_requires_lock;
1979e5dd7070Spatrick           break;
1980e5dd7070Spatrick         case POK_VarDereference:
1981e5dd7070Spatrick           DiagID = diag::warn_var_deref_requires_lock;
1982e5dd7070Spatrick           break;
1983e5dd7070Spatrick         case POK_FunctionCall:
1984e5dd7070Spatrick           DiagID = diag::warn_fun_requires_lock;
1985e5dd7070Spatrick           break;
1986e5dd7070Spatrick         case POK_PassByRef:
1987e5dd7070Spatrick           DiagID = diag::warn_guarded_pass_by_reference;
1988e5dd7070Spatrick           break;
1989e5dd7070Spatrick         case POK_PtPassByRef:
1990e5dd7070Spatrick           DiagID = diag::warn_pt_guarded_pass_by_reference;
1991e5dd7070Spatrick           break;
1992e5dd7070Spatrick       }
1993e5dd7070Spatrick       PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind
1994e5dd7070Spatrick                                                        << D
1995e5dd7070Spatrick                                                        << LockName << LK);
1996e5dd7070Spatrick       if (Verbose && POK == POK_VarAccess) {
1997e5dd7070Spatrick         PartialDiagnosticAt Note(D->getLocation(),
1998e5dd7070Spatrick                                  S.PDiag(diag::note_guarded_by_declared_here));
1999e5dd7070Spatrick         Warnings.emplace_back(std::move(Warning), getNotes(Note));
2000e5dd7070Spatrick       } else
2001e5dd7070Spatrick         Warnings.emplace_back(std::move(Warning), getNotes());
2002e5dd7070Spatrick     }
2003e5dd7070Spatrick   }
2004e5dd7070Spatrick 
handleNegativeNotHeld(StringRef Kind,Name LockName,Name Neg,SourceLocation Loc)2005e5dd7070Spatrick   void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
2006e5dd7070Spatrick                              SourceLocation Loc) override {
2007e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc,
2008e5dd7070Spatrick         S.PDiag(diag::warn_acquire_requires_negative_cap)
2009e5dd7070Spatrick         << Kind << LockName << Neg);
2010e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning), getNotes());
2011e5dd7070Spatrick   }
2012e5dd7070Spatrick 
handleNegativeNotHeld(const NamedDecl * D,Name LockName,SourceLocation Loc)2013a9ac8606Spatrick   void handleNegativeNotHeld(const NamedDecl *D, Name LockName,
2014a9ac8606Spatrick                              SourceLocation Loc) override {
2015a9ac8606Spatrick     PartialDiagnosticAt Warning(
2016a9ac8606Spatrick         Loc, S.PDiag(diag::warn_fun_requires_negative_cap) << D << LockName);
2017a9ac8606Spatrick     Warnings.emplace_back(std::move(Warning), getNotes());
2018a9ac8606Spatrick   }
2019a9ac8606Spatrick 
handleFunExcludesLock(StringRef Kind,Name FunName,Name LockName,SourceLocation Loc)2020e5dd7070Spatrick   void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
2021e5dd7070Spatrick                              SourceLocation Loc) override {
2022e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_fun_excludes_mutex)
2023e5dd7070Spatrick                                          << Kind << FunName << LockName);
2024e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning), getNotes());
2025e5dd7070Spatrick   }
2026e5dd7070Spatrick 
handleLockAcquiredBefore(StringRef Kind,Name L1Name,Name L2Name,SourceLocation Loc)2027e5dd7070Spatrick   void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
2028e5dd7070Spatrick                                 SourceLocation Loc) override {
2029e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc,
2030e5dd7070Spatrick       S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
2031e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning), getNotes());
2032e5dd7070Spatrick   }
2033e5dd7070Spatrick 
handleBeforeAfterCycle(Name L1Name,SourceLocation Loc)2034e5dd7070Spatrick   void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) override {
2035e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc,
2036e5dd7070Spatrick       S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
2037e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning), getNotes());
2038e5dd7070Spatrick   }
2039e5dd7070Spatrick 
enterFunction(const FunctionDecl * FD)2040e5dd7070Spatrick   void enterFunction(const FunctionDecl* FD) override {
2041e5dd7070Spatrick     CurrentFunction = FD;
2042e5dd7070Spatrick   }
2043e5dd7070Spatrick 
leaveFunction(const FunctionDecl * FD)2044e5dd7070Spatrick   void leaveFunction(const FunctionDecl* FD) override {
2045e5dd7070Spatrick     CurrentFunction = nullptr;
2046e5dd7070Spatrick   }
2047e5dd7070Spatrick };
2048e5dd7070Spatrick } // anonymous namespace
2049e5dd7070Spatrick } // namespace threadSafety
2050e5dd7070Spatrick } // namespace clang
2051e5dd7070Spatrick 
2052e5dd7070Spatrick //===----------------------------------------------------------------------===//
2053e5dd7070Spatrick // -Wconsumed
2054e5dd7070Spatrick //===----------------------------------------------------------------------===//
2055e5dd7070Spatrick 
2056e5dd7070Spatrick namespace clang {
2057e5dd7070Spatrick namespace consumed {
2058e5dd7070Spatrick namespace {
2059e5dd7070Spatrick class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
2060e5dd7070Spatrick 
2061e5dd7070Spatrick   Sema &S;
2062e5dd7070Spatrick   DiagList Warnings;
2063e5dd7070Spatrick 
2064e5dd7070Spatrick public:
2065e5dd7070Spatrick 
ConsumedWarningsHandler(Sema & S)2066e5dd7070Spatrick   ConsumedWarningsHandler(Sema &S) : S(S) {}
2067e5dd7070Spatrick 
emitDiagnostics()2068e5dd7070Spatrick   void emitDiagnostics() override {
2069e5dd7070Spatrick     Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
2070e5dd7070Spatrick     for (const auto &Diag : Warnings) {
2071e5dd7070Spatrick       S.Diag(Diag.first.first, Diag.first.second);
2072e5dd7070Spatrick       for (const auto &Note : Diag.second)
2073e5dd7070Spatrick         S.Diag(Note.first, Note.second);
2074e5dd7070Spatrick     }
2075e5dd7070Spatrick   }
2076e5dd7070Spatrick 
warnLoopStateMismatch(SourceLocation Loc,StringRef VariableName)2077e5dd7070Spatrick   void warnLoopStateMismatch(SourceLocation Loc,
2078e5dd7070Spatrick                              StringRef VariableName) override {
2079e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch) <<
2080e5dd7070Spatrick       VariableName);
2081e5dd7070Spatrick 
2082e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning), OptionalNotes());
2083e5dd7070Spatrick   }
2084e5dd7070Spatrick 
warnParamReturnTypestateMismatch(SourceLocation Loc,StringRef VariableName,StringRef ExpectedState,StringRef ObservedState)2085e5dd7070Spatrick   void warnParamReturnTypestateMismatch(SourceLocation Loc,
2086e5dd7070Spatrick                                         StringRef VariableName,
2087e5dd7070Spatrick                                         StringRef ExpectedState,
2088e5dd7070Spatrick                                         StringRef ObservedState) override {
2089e5dd7070Spatrick 
2090e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc, S.PDiag(
2091e5dd7070Spatrick       diag::warn_param_return_typestate_mismatch) << VariableName <<
2092e5dd7070Spatrick         ExpectedState << ObservedState);
2093e5dd7070Spatrick 
2094e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning), OptionalNotes());
2095e5dd7070Spatrick   }
2096e5dd7070Spatrick 
warnParamTypestateMismatch(SourceLocation Loc,StringRef ExpectedState,StringRef ObservedState)2097e5dd7070Spatrick   void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
2098e5dd7070Spatrick                                   StringRef ObservedState) override {
2099e5dd7070Spatrick 
2100e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc, S.PDiag(
2101e5dd7070Spatrick       diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
2102e5dd7070Spatrick 
2103e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning), OptionalNotes());
2104e5dd7070Spatrick   }
2105e5dd7070Spatrick 
warnReturnTypestateForUnconsumableType(SourceLocation Loc,StringRef TypeName)2106e5dd7070Spatrick   void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
2107e5dd7070Spatrick                                               StringRef TypeName) override {
2108e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc, S.PDiag(
2109e5dd7070Spatrick       diag::warn_return_typestate_for_unconsumable_type) << TypeName);
2110e5dd7070Spatrick 
2111e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning), OptionalNotes());
2112e5dd7070Spatrick   }
2113e5dd7070Spatrick 
warnReturnTypestateMismatch(SourceLocation Loc,StringRef ExpectedState,StringRef ObservedState)2114e5dd7070Spatrick   void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
2115e5dd7070Spatrick                                    StringRef ObservedState) override {
2116e5dd7070Spatrick 
2117e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc, S.PDiag(
2118e5dd7070Spatrick       diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
2119e5dd7070Spatrick 
2120e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning), OptionalNotes());
2121e5dd7070Spatrick   }
2122e5dd7070Spatrick 
warnUseOfTempInInvalidState(StringRef MethodName,StringRef State,SourceLocation Loc)2123e5dd7070Spatrick   void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
2124e5dd7070Spatrick                                    SourceLocation Loc) override {
2125e5dd7070Spatrick 
2126e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc, S.PDiag(
2127e5dd7070Spatrick       diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
2128e5dd7070Spatrick 
2129e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning), OptionalNotes());
2130e5dd7070Spatrick   }
2131e5dd7070Spatrick 
warnUseInInvalidState(StringRef MethodName,StringRef VariableName,StringRef State,SourceLocation Loc)2132e5dd7070Spatrick   void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
2133e5dd7070Spatrick                              StringRef State, SourceLocation Loc) override {
2134e5dd7070Spatrick 
2135e5dd7070Spatrick     PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) <<
2136e5dd7070Spatrick                                 MethodName << VariableName << State);
2137e5dd7070Spatrick 
2138e5dd7070Spatrick     Warnings.emplace_back(std::move(Warning), OptionalNotes());
2139e5dd7070Spatrick   }
2140e5dd7070Spatrick };
2141e5dd7070Spatrick } // anonymous namespace
2142e5dd7070Spatrick } // namespace consumed
2143e5dd7070Spatrick } // namespace clang
2144e5dd7070Spatrick 
2145e5dd7070Spatrick //===----------------------------------------------------------------------===//
2146*12c85518Srobert // Unsafe buffer usage analysis.
2147*12c85518Srobert //===----------------------------------------------------------------------===//
2148*12c85518Srobert 
2149*12c85518Srobert namespace {
2150*12c85518Srobert class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
2151*12c85518Srobert   Sema &S;
2152*12c85518Srobert 
2153*12c85518Srobert public:
UnsafeBufferUsageReporter(Sema & S)2154*12c85518Srobert   UnsafeBufferUsageReporter(Sema &S) : S(S) {}
2155*12c85518Srobert 
handleUnsafeOperation(const Stmt * Operation,bool IsRelatedToDecl)2156*12c85518Srobert   void handleUnsafeOperation(const Stmt *Operation,
2157*12c85518Srobert                              bool IsRelatedToDecl) override {
2158*12c85518Srobert     SourceLocation Loc;
2159*12c85518Srobert     SourceRange Range;
2160*12c85518Srobert     unsigned MsgParam = 0;
2161*12c85518Srobert     if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
2162*12c85518Srobert       Loc = ASE->getBase()->getExprLoc();
2163*12c85518Srobert       Range = ASE->getBase()->getSourceRange();
2164*12c85518Srobert       MsgParam = 2;
2165*12c85518Srobert     } else if (const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
2166*12c85518Srobert       BinaryOperator::Opcode Op = BO->getOpcode();
2167*12c85518Srobert       if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
2168*12c85518Srobert           Op == BO_SubAssign) {
2169*12c85518Srobert         if (BO->getRHS()->getType()->isIntegerType()) {
2170*12c85518Srobert           Loc = BO->getLHS()->getExprLoc();
2171*12c85518Srobert           Range = BO->getLHS()->getSourceRange();
2172*12c85518Srobert         } else {
2173*12c85518Srobert           Loc = BO->getRHS()->getExprLoc();
2174*12c85518Srobert           Range = BO->getRHS()->getSourceRange();
2175*12c85518Srobert         }
2176*12c85518Srobert         MsgParam = 1;
2177*12c85518Srobert       }
2178*12c85518Srobert     } else if (const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
2179*12c85518Srobert       UnaryOperator::Opcode Op = UO->getOpcode();
2180*12c85518Srobert       if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
2181*12c85518Srobert           Op == UO_PostDec) {
2182*12c85518Srobert         Loc = UO->getSubExpr()->getExprLoc();
2183*12c85518Srobert         Range = UO->getSubExpr()->getSourceRange();
2184*12c85518Srobert         MsgParam = 1;
2185*12c85518Srobert       }
2186*12c85518Srobert     } else {
2187*12c85518Srobert       Loc = Operation->getBeginLoc();
2188*12c85518Srobert       Range = Operation->getSourceRange();
2189*12c85518Srobert     }
2190*12c85518Srobert     if (IsRelatedToDecl)
2191*12c85518Srobert       S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;
2192*12c85518Srobert     else
2193*12c85518Srobert       S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam << Range;
2194*12c85518Srobert   }
2195*12c85518Srobert 
2196*12c85518Srobert   // FIXME: rename to handleUnsafeVariable
handleFixableVariable(const VarDecl * Variable,FixItList && Fixes)2197*12c85518Srobert   void handleFixableVariable(const VarDecl *Variable,
2198*12c85518Srobert                              FixItList &&Fixes) override {
2199*12c85518Srobert     const auto &D =
2200*12c85518Srobert         S.Diag(Variable->getLocation(), diag::warn_unsafe_buffer_variable);
2201*12c85518Srobert     D << Variable;
2202*12c85518Srobert     D << (Variable->getType()->isPointerType() ? 0 : 1);
2203*12c85518Srobert     D << Variable->getSourceRange();
2204*12c85518Srobert     for (const auto &F : Fixes)
2205*12c85518Srobert       D << F;
2206*12c85518Srobert   }
2207*12c85518Srobert };
2208*12c85518Srobert } // namespace
2209*12c85518Srobert 
2210*12c85518Srobert //===----------------------------------------------------------------------===//
2211e5dd7070Spatrick // AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based
2212e5dd7070Spatrick //  warnings on a function, method, or block.
2213e5dd7070Spatrick //===----------------------------------------------------------------------===//
2214e5dd7070Spatrick 
Policy()2215a9ac8606Spatrick sema::AnalysisBasedWarnings::Policy::Policy() {
2216e5dd7070Spatrick   enableCheckFallThrough = 1;
2217e5dd7070Spatrick   enableCheckUnreachable = 0;
2218e5dd7070Spatrick   enableThreadSafetyAnalysis = 0;
2219e5dd7070Spatrick   enableConsumedAnalysis = 0;
2220e5dd7070Spatrick }
2221e5dd7070Spatrick 
2222a9ac8606Spatrick /// InterProceduralData aims to be a storage of whatever data should be passed
2223a9ac8606Spatrick /// between analyses of different functions.
2224a9ac8606Spatrick ///
2225a9ac8606Spatrick /// At the moment, its primary goal is to make the information gathered during
2226a9ac8606Spatrick /// the analysis of the blocks available during the analysis of the enclosing
2227a9ac8606Spatrick /// function.  This is important due to the fact that blocks are analyzed before
2228a9ac8606Spatrick /// the enclosed function is even parsed fully, so it is not viable to access
2229a9ac8606Spatrick /// anything in the outer scope while analyzing the block.  On the other hand,
2230a9ac8606Spatrick /// re-building CFG for blocks and re-analyzing them when we do have all the
2231a9ac8606Spatrick /// information (i.e. during the analysis of the enclosing function) seems to be
2232a9ac8606Spatrick /// ill-designed.
2233a9ac8606Spatrick class sema::AnalysisBasedWarnings::InterProceduralData {
2234a9ac8606Spatrick public:
2235a9ac8606Spatrick   // It is important to analyze blocks within functions because it's a very
2236a9ac8606Spatrick   // common pattern to capture completion handler parameters by blocks.
2237a9ac8606Spatrick   CalledOnceInterProceduralData CalledOnceData;
2238a9ac8606Spatrick };
2239a9ac8606Spatrick 
isEnabled(DiagnosticsEngine & D,unsigned diag)2240e5dd7070Spatrick static unsigned isEnabled(DiagnosticsEngine &D, unsigned diag) {
2241e5dd7070Spatrick   return (unsigned)!D.isIgnored(diag, SourceLocation());
2242e5dd7070Spatrick }
2243e5dd7070Spatrick 
AnalysisBasedWarnings(Sema & s)2244a9ac8606Spatrick sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
2245a9ac8606Spatrick     : S(s), IPData(std::make_unique<InterProceduralData>()),
2246a9ac8606Spatrick       NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),
2247a9ac8606Spatrick       MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),
2248a9ac8606Spatrick       NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
2249e5dd7070Spatrick       NumUninitAnalysisBlockVisits(0),
2250e5dd7070Spatrick       MaxUninitAnalysisBlockVisitsPerFunction(0) {
2251e5dd7070Spatrick 
2252e5dd7070Spatrick   using namespace diag;
2253e5dd7070Spatrick   DiagnosticsEngine &D = S.getDiagnostics();
2254e5dd7070Spatrick 
2255e5dd7070Spatrick   DefaultPolicy.enableCheckUnreachable =
2256a9ac8606Spatrick       isEnabled(D, warn_unreachable) || isEnabled(D, warn_unreachable_break) ||
2257e5dd7070Spatrick       isEnabled(D, warn_unreachable_return) ||
2258e5dd7070Spatrick       isEnabled(D, warn_unreachable_loop_increment);
2259e5dd7070Spatrick 
2260a9ac8606Spatrick   DefaultPolicy.enableThreadSafetyAnalysis = isEnabled(D, warn_double_lock);
2261e5dd7070Spatrick 
2262e5dd7070Spatrick   DefaultPolicy.enableConsumedAnalysis =
2263e5dd7070Spatrick       isEnabled(D, warn_use_in_invalid_state);
2264e5dd7070Spatrick }
2265e5dd7070Spatrick 
2266a9ac8606Spatrick // We need this here for unique_ptr with forward declared class.
2267a9ac8606Spatrick sema::AnalysisBasedWarnings::~AnalysisBasedWarnings() = default;
2268a9ac8606Spatrick 
flushDiagnostics(Sema & S,const sema::FunctionScopeInfo * fscope)2269e5dd7070Spatrick static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope) {
2270e5dd7070Spatrick   for (const auto &D : fscope->PossiblyUnreachableDiags)
2271e5dd7070Spatrick     S.Diag(D.Loc, D.PD);
2272e5dd7070Spatrick }
2273e5dd7070Spatrick 
IssueWarnings(sema::AnalysisBasedWarnings::Policy P,sema::FunctionScopeInfo * fscope,const Decl * D,QualType BlockType)2274a9ac8606Spatrick void clang::sema::AnalysisBasedWarnings::IssueWarnings(
2275a9ac8606Spatrick     sema::AnalysisBasedWarnings::Policy P, sema::FunctionScopeInfo *fscope,
2276e5dd7070Spatrick     const Decl *D, QualType BlockType) {
2277e5dd7070Spatrick 
2278e5dd7070Spatrick   // We avoid doing analysis-based warnings when there are errors for
2279e5dd7070Spatrick   // two reasons:
2280e5dd7070Spatrick   // (1) The CFGs often can't be constructed (if the body is invalid), so
2281e5dd7070Spatrick   //     don't bother trying.
2282e5dd7070Spatrick   // (2) The code already has problems; running the analysis just takes more
2283e5dd7070Spatrick   //     time.
2284e5dd7070Spatrick   DiagnosticsEngine &Diags = S.getDiagnostics();
2285e5dd7070Spatrick 
2286e5dd7070Spatrick   // Do not do any analysis if we are going to just ignore them.
2287e5dd7070Spatrick   if (Diags.getIgnoreAllWarnings() ||
2288e5dd7070Spatrick       (Diags.getSuppressSystemWarnings() &&
2289e5dd7070Spatrick        S.SourceMgr.isInSystemHeader(D->getLocation())))
2290e5dd7070Spatrick     return;
2291e5dd7070Spatrick 
2292e5dd7070Spatrick   // For code in dependent contexts, we'll do this at instantiation time.
2293e5dd7070Spatrick   if (cast<DeclContext>(D)->isDependentContext())
2294e5dd7070Spatrick     return;
2295e5dd7070Spatrick 
2296a9ac8606Spatrick   if (S.hasUncompilableErrorOccurred()) {
2297e5dd7070Spatrick     // Flush out any possibly unreachable diagnostics.
2298e5dd7070Spatrick     flushDiagnostics(S, fscope);
2299e5dd7070Spatrick     return;
2300e5dd7070Spatrick   }
2301e5dd7070Spatrick 
2302e5dd7070Spatrick   const Stmt *Body = D->getBody();
2303e5dd7070Spatrick   assert(Body);
2304e5dd7070Spatrick 
2305e5dd7070Spatrick   // Construct the analysis context with the specified CFG build options.
2306e5dd7070Spatrick   AnalysisDeclContext AC(/* AnalysisDeclContextManager */ nullptr, D);
2307e5dd7070Spatrick 
2308e5dd7070Spatrick   // Don't generate EH edges for CallExprs as we'd like to avoid the n^2
2309e5dd7070Spatrick   // explosion for destructors that can result and the compile time hit.
2310e5dd7070Spatrick   AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true;
2311e5dd7070Spatrick   AC.getCFGBuildOptions().AddEHEdges = false;
2312e5dd7070Spatrick   AC.getCFGBuildOptions().AddInitializers = true;
2313e5dd7070Spatrick   AC.getCFGBuildOptions().AddImplicitDtors = true;
2314e5dd7070Spatrick   AC.getCFGBuildOptions().AddTemporaryDtors = true;
2315e5dd7070Spatrick   AC.getCFGBuildOptions().AddCXXNewAllocator = false;
2316e5dd7070Spatrick   AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true;
2317e5dd7070Spatrick 
2318e5dd7070Spatrick   // Force that certain expressions appear as CFGElements in the CFG.  This
2319e5dd7070Spatrick   // is used to speed up various analyses.
2320e5dd7070Spatrick   // FIXME: This isn't the right factoring.  This is here for initial
2321e5dd7070Spatrick   // prototyping, but we need a way for analyses to say what expressions they
2322e5dd7070Spatrick   // expect to always be CFGElements and then fill in the BuildOptions
2323e5dd7070Spatrick   // appropriately.  This is essentially a layering violation.
2324e5dd7070Spatrick   if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||
2325e5dd7070Spatrick       P.enableConsumedAnalysis) {
2326e5dd7070Spatrick     // Unreachable code analysis and thread safety require a linearized CFG.
2327e5dd7070Spatrick     AC.getCFGBuildOptions().setAllAlwaysAdd();
2328e5dd7070Spatrick   }
2329e5dd7070Spatrick   else {
2330e5dd7070Spatrick     AC.getCFGBuildOptions()
2331e5dd7070Spatrick       .setAlwaysAdd(Stmt::BinaryOperatorClass)
2332e5dd7070Spatrick       .setAlwaysAdd(Stmt::CompoundAssignOperatorClass)
2333e5dd7070Spatrick       .setAlwaysAdd(Stmt::BlockExprClass)
2334e5dd7070Spatrick       .setAlwaysAdd(Stmt::CStyleCastExprClass)
2335e5dd7070Spatrick       .setAlwaysAdd(Stmt::DeclRefExprClass)
2336e5dd7070Spatrick       .setAlwaysAdd(Stmt::ImplicitCastExprClass)
2337*12c85518Srobert       .setAlwaysAdd(Stmt::UnaryOperatorClass);
2338e5dd7070Spatrick   }
2339e5dd7070Spatrick 
2340e5dd7070Spatrick   // Install the logical handler.
2341*12c85518Srobert   std::optional<LogicalErrorHandler> LEH;
2342e5dd7070Spatrick   if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
2343e5dd7070Spatrick     LEH.emplace(S);
2344e5dd7070Spatrick     AC.getCFGBuildOptions().Observer = &*LEH;
2345e5dd7070Spatrick   }
2346e5dd7070Spatrick 
2347e5dd7070Spatrick   // Emit delayed diagnostics.
2348e5dd7070Spatrick   if (!fscope->PossiblyUnreachableDiags.empty()) {
2349e5dd7070Spatrick     bool analyzed = false;
2350e5dd7070Spatrick 
2351e5dd7070Spatrick     // Register the expressions with the CFGBuilder.
2352e5dd7070Spatrick     for (const auto &D : fscope->PossiblyUnreachableDiags) {
2353e5dd7070Spatrick       for (const Stmt *S : D.Stmts)
2354e5dd7070Spatrick         AC.registerForcedBlockExpression(S);
2355e5dd7070Spatrick     }
2356e5dd7070Spatrick 
2357e5dd7070Spatrick     if (AC.getCFG()) {
2358e5dd7070Spatrick       analyzed = true;
2359e5dd7070Spatrick       for (const auto &D : fscope->PossiblyUnreachableDiags) {
2360e5dd7070Spatrick         bool AllReachable = true;
2361e5dd7070Spatrick         for (const Stmt *S : D.Stmts) {
2362e5dd7070Spatrick           const CFGBlock *block = AC.getBlockForRegisteredExpression(S);
2363e5dd7070Spatrick           CFGReverseBlockReachabilityAnalysis *cra =
2364e5dd7070Spatrick               AC.getCFGReachablityAnalysis();
2365e5dd7070Spatrick           // FIXME: We should be able to assert that block is non-null, but
2366e5dd7070Spatrick           // the CFG analysis can skip potentially-evaluated expressions in
2367e5dd7070Spatrick           // edge cases; see test/Sema/vla-2.c.
2368e5dd7070Spatrick           if (block && cra) {
2369e5dd7070Spatrick             // Can this block be reached from the entrance?
2370e5dd7070Spatrick             if (!cra->isReachable(&AC.getCFG()->getEntry(), block)) {
2371e5dd7070Spatrick               AllReachable = false;
2372e5dd7070Spatrick               break;
2373e5dd7070Spatrick             }
2374e5dd7070Spatrick           }
2375e5dd7070Spatrick           // If we cannot map to a basic block, assume the statement is
2376e5dd7070Spatrick           // reachable.
2377e5dd7070Spatrick         }
2378e5dd7070Spatrick 
2379e5dd7070Spatrick         if (AllReachable)
2380e5dd7070Spatrick           S.Diag(D.Loc, D.PD);
2381e5dd7070Spatrick       }
2382e5dd7070Spatrick     }
2383e5dd7070Spatrick 
2384e5dd7070Spatrick     if (!analyzed)
2385e5dd7070Spatrick       flushDiagnostics(S, fscope);
2386e5dd7070Spatrick   }
2387e5dd7070Spatrick 
2388e5dd7070Spatrick   // Warning: check missing 'return'
2389e5dd7070Spatrick   if (P.enableCheckFallThrough) {
2390e5dd7070Spatrick     const CheckFallThroughDiagnostics &CD =
2391e5dd7070Spatrick         (isa<BlockDecl>(D)
2392e5dd7070Spatrick              ? CheckFallThroughDiagnostics::MakeForBlock()
2393e5dd7070Spatrick              : (isa<CXXMethodDecl>(D) &&
2394e5dd7070Spatrick                 cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call &&
2395e5dd7070Spatrick                 cast<CXXMethodDecl>(D)->getParent()->isLambda())
2396e5dd7070Spatrick                    ? CheckFallThroughDiagnostics::MakeForLambda()
2397e5dd7070Spatrick                    : (fscope->isCoroutine()
2398e5dd7070Spatrick                           ? CheckFallThroughDiagnostics::MakeForCoroutine(D)
2399e5dd7070Spatrick                           : CheckFallThroughDiagnostics::MakeForFunction(D)));
2400e5dd7070Spatrick     CheckFallThroughForBody(S, D, Body, BlockType, CD, AC, fscope);
2401e5dd7070Spatrick   }
2402e5dd7070Spatrick 
2403e5dd7070Spatrick   // Warning: check for unreachable code
2404e5dd7070Spatrick   if (P.enableCheckUnreachable) {
2405e5dd7070Spatrick     // Only check for unreachable code on non-template instantiations.
2406e5dd7070Spatrick     // Different template instantiations can effectively change the control-flow
2407e5dd7070Spatrick     // and it is very difficult to prove that a snippet of code in a template
2408e5dd7070Spatrick     // is unreachable for all instantiations.
2409e5dd7070Spatrick     bool isTemplateInstantiation = false;
2410e5dd7070Spatrick     if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
2411e5dd7070Spatrick       isTemplateInstantiation = Function->isTemplateInstantiation();
2412e5dd7070Spatrick     if (!isTemplateInstantiation)
2413e5dd7070Spatrick       CheckUnreachable(S, AC);
2414e5dd7070Spatrick   }
2415e5dd7070Spatrick 
2416e5dd7070Spatrick   // Check for thread safety violations
2417e5dd7070Spatrick   if (P.enableThreadSafetyAnalysis) {
2418e5dd7070Spatrick     SourceLocation FL = AC.getDecl()->getLocation();
2419e5dd7070Spatrick     SourceLocation FEL = AC.getDecl()->getEndLoc();
2420e5dd7070Spatrick     threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
2421e5dd7070Spatrick     if (!Diags.isIgnored(diag::warn_thread_safety_beta, D->getBeginLoc()))
2422e5dd7070Spatrick       Reporter.setIssueBetaWarnings(true);
2423e5dd7070Spatrick     if (!Diags.isIgnored(diag::warn_thread_safety_verbose, D->getBeginLoc()))
2424e5dd7070Spatrick       Reporter.setVerbose(true);
2425e5dd7070Spatrick 
2426e5dd7070Spatrick     threadSafety::runThreadSafetyAnalysis(AC, Reporter,
2427e5dd7070Spatrick                                           &S.ThreadSafetyDeclCache);
2428e5dd7070Spatrick     Reporter.emitDiagnostics();
2429e5dd7070Spatrick   }
2430e5dd7070Spatrick 
2431e5dd7070Spatrick   // Check for violations of consumed properties.
2432e5dd7070Spatrick   if (P.enableConsumedAnalysis) {
2433e5dd7070Spatrick     consumed::ConsumedWarningsHandler WarningHandler(S);
2434e5dd7070Spatrick     consumed::ConsumedAnalyzer Analyzer(WarningHandler);
2435e5dd7070Spatrick     Analyzer.run(AC);
2436e5dd7070Spatrick   }
2437e5dd7070Spatrick 
2438e5dd7070Spatrick   if (!Diags.isIgnored(diag::warn_uninit_var, D->getBeginLoc()) ||
2439e5dd7070Spatrick       !Diags.isIgnored(diag::warn_sometimes_uninit_var, D->getBeginLoc()) ||
2440ec727ea7Spatrick       !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getBeginLoc()) ||
2441ec727ea7Spatrick       !Diags.isIgnored(diag::warn_uninit_const_reference, D->getBeginLoc())) {
2442e5dd7070Spatrick     if (CFG *cfg = AC.getCFG()) {
2443e5dd7070Spatrick       UninitValsDiagReporter reporter(S);
2444e5dd7070Spatrick       UninitVariablesAnalysisStats stats;
2445e5dd7070Spatrick       std::memset(&stats, 0, sizeof(UninitVariablesAnalysisStats));
2446e5dd7070Spatrick       runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC,
2447e5dd7070Spatrick                                         reporter, stats);
2448e5dd7070Spatrick 
2449e5dd7070Spatrick       if (S.CollectStats && stats.NumVariablesAnalyzed > 0) {
2450e5dd7070Spatrick         ++NumUninitAnalysisFunctions;
2451e5dd7070Spatrick         NumUninitAnalysisVariables += stats.NumVariablesAnalyzed;
2452e5dd7070Spatrick         NumUninitAnalysisBlockVisits += stats.NumBlockVisits;
2453e5dd7070Spatrick         MaxUninitAnalysisVariablesPerFunction =
2454e5dd7070Spatrick             std::max(MaxUninitAnalysisVariablesPerFunction,
2455e5dd7070Spatrick                      stats.NumVariablesAnalyzed);
2456e5dd7070Spatrick         MaxUninitAnalysisBlockVisitsPerFunction =
2457e5dd7070Spatrick             std::max(MaxUninitAnalysisBlockVisitsPerFunction,
2458e5dd7070Spatrick                      stats.NumBlockVisits);
2459e5dd7070Spatrick       }
2460e5dd7070Spatrick     }
2461e5dd7070Spatrick   }
2462e5dd7070Spatrick 
2463a9ac8606Spatrick   // Check for violations of "called once" parameter properties.
2464a9ac8606Spatrick   if (S.getLangOpts().ObjC && !S.getLangOpts().CPlusPlus &&
2465a9ac8606Spatrick       shouldAnalyzeCalledOnceParameters(Diags, D->getBeginLoc())) {
2466a9ac8606Spatrick     if (AC.getCFG()) {
2467a9ac8606Spatrick       CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);
2468a9ac8606Spatrick       checkCalledOnceParameters(
2469a9ac8606Spatrick           AC, Reporter,
2470a9ac8606Spatrick           shouldAnalyzeCalledOnceConventions(Diags, D->getBeginLoc()));
2471a9ac8606Spatrick     }
2472a9ac8606Spatrick   }
2473a9ac8606Spatrick 
2474e5dd7070Spatrick   bool FallThroughDiagFull =
2475e5dd7070Spatrick       !Diags.isIgnored(diag::warn_unannotated_fallthrough, D->getBeginLoc());
2476e5dd7070Spatrick   bool FallThroughDiagPerFunction = !Diags.isIgnored(
2477e5dd7070Spatrick       diag::warn_unannotated_fallthrough_per_function, D->getBeginLoc());
2478e5dd7070Spatrick   if (FallThroughDiagFull || FallThroughDiagPerFunction ||
2479e5dd7070Spatrick       fscope->HasFallthroughStmt) {
2480e5dd7070Spatrick     DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull);
2481e5dd7070Spatrick   }
2482e5dd7070Spatrick 
2483e5dd7070Spatrick   if (S.getLangOpts().ObjCWeak &&
2484e5dd7070Spatrick       !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, D->getBeginLoc()))
2485e5dd7070Spatrick     diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap());
2486e5dd7070Spatrick 
2487e5dd7070Spatrick 
2488e5dd7070Spatrick   // Check for infinite self-recursion in functions
2489e5dd7070Spatrick   if (!Diags.isIgnored(diag::warn_infinite_recursive_function,
2490e5dd7070Spatrick                        D->getBeginLoc())) {
2491e5dd7070Spatrick     if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
2492e5dd7070Spatrick       checkRecursiveFunction(S, FD, Body, AC);
2493e5dd7070Spatrick     }
2494e5dd7070Spatrick   }
2495e5dd7070Spatrick 
2496e5dd7070Spatrick   // Check for throw out of non-throwing function.
2497e5dd7070Spatrick   if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getBeginLoc()))
2498e5dd7070Spatrick     if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
2499e5dd7070Spatrick       if (S.getLangOpts().CPlusPlus && isNoexcept(FD))
2500e5dd7070Spatrick         checkThrowInNonThrowingFunc(S, FD, AC);
2501e5dd7070Spatrick 
2502*12c85518Srobert   // Emit unsafe buffer usage warnings and fixits.
2503*12c85518Srobert   if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, D->getBeginLoc()) ||
2504*12c85518Srobert       !Diags.isIgnored(diag::warn_unsafe_buffer_variable, D->getBeginLoc())) {
2505*12c85518Srobert     UnsafeBufferUsageReporter R(S);
2506*12c85518Srobert     checkUnsafeBufferUsage(D, R);
2507*12c85518Srobert   }
2508*12c85518Srobert 
2509e5dd7070Spatrick   // If none of the previous checks caused a CFG build, trigger one here
2510e5dd7070Spatrick   // for the logical error handler.
2511e5dd7070Spatrick   if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
2512e5dd7070Spatrick     AC.getCFG();
2513e5dd7070Spatrick   }
2514e5dd7070Spatrick 
2515e5dd7070Spatrick   // Collect statistics about the CFG if it was built.
2516e5dd7070Spatrick   if (S.CollectStats && AC.isCFGBuilt()) {
2517e5dd7070Spatrick     ++NumFunctionsAnalyzed;
2518e5dd7070Spatrick     if (CFG *cfg = AC.getCFG()) {
2519e5dd7070Spatrick       // If we successfully built a CFG for this context, record some more
2520e5dd7070Spatrick       // detail information about it.
2521e5dd7070Spatrick       NumCFGBlocks += cfg->getNumBlockIDs();
2522e5dd7070Spatrick       MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
2523e5dd7070Spatrick                                          cfg->getNumBlockIDs());
2524e5dd7070Spatrick     } else {
2525e5dd7070Spatrick       ++NumFunctionsWithBadCFGs;
2526e5dd7070Spatrick     }
2527e5dd7070Spatrick   }
2528e5dd7070Spatrick }
2529e5dd7070Spatrick 
PrintStats() const2530e5dd7070Spatrick void clang::sema::AnalysisBasedWarnings::PrintStats() const {
2531e5dd7070Spatrick   llvm::errs() << "\n*** Analysis Based Warnings Stats:\n";
2532e5dd7070Spatrick 
2533e5dd7070Spatrick   unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
2534e5dd7070Spatrick   unsigned AvgCFGBlocksPerFunction =
2535e5dd7070Spatrick       !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
2536e5dd7070Spatrick   llvm::errs() << NumFunctionsAnalyzed << " functions analyzed ("
2537e5dd7070Spatrick                << NumFunctionsWithBadCFGs << " w/o CFGs).\n"
2538e5dd7070Spatrick                << "  " << NumCFGBlocks << " CFG blocks built.\n"
2539e5dd7070Spatrick                << "  " << AvgCFGBlocksPerFunction
2540e5dd7070Spatrick                << " average CFG blocks per function.\n"
2541e5dd7070Spatrick                << "  " << MaxCFGBlocksPerFunction
2542e5dd7070Spatrick                << " max CFG blocks per function.\n";
2543e5dd7070Spatrick 
2544e5dd7070Spatrick   unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
2545e5dd7070Spatrick       : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
2546e5dd7070Spatrick   unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
2547e5dd7070Spatrick       : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
2548e5dd7070Spatrick   llvm::errs() << NumUninitAnalysisFunctions
2549e5dd7070Spatrick                << " functions analyzed for uninitialiazed variables\n"
2550e5dd7070Spatrick                << "  " << NumUninitAnalysisVariables << " variables analyzed.\n"
2551e5dd7070Spatrick                << "  " << AvgUninitVariablesPerFunction
2552e5dd7070Spatrick                << " average variables per function.\n"
2553e5dd7070Spatrick                << "  " << MaxUninitAnalysisVariablesPerFunction
2554e5dd7070Spatrick                << " max variables per function.\n"
2555e5dd7070Spatrick                << "  " << NumUninitAnalysisBlockVisits << " block visits.\n"
2556e5dd7070Spatrick                << "  " << AvgUninitBlockVisitsPerFunction
2557e5dd7070Spatrick                << " average block visits per function.\n"
2558e5dd7070Spatrick                << "  " << MaxUninitAnalysisBlockVisitsPerFunction
2559e5dd7070Spatrick                << " max block visits per function.\n";
2560e5dd7070Spatrick }
2561