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