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