3207 lines · cpp
1//=== AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis ------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines analysis_warnings::[Policy,Executor].10// Together they are used by Sema to issue warnings based on inexpensive11// static analysis algorithms in libAnalysis.12//13//===----------------------------------------------------------------------===//14 15#include "clang/Sema/AnalysisBasedWarnings.h"16#include "clang/AST/Decl.h"17#include "clang/AST/DeclCXX.h"18#include "clang/AST/DeclObjC.h"19#include "clang/AST/DynamicRecursiveASTVisitor.h"20#include "clang/AST/EvaluatedExprVisitor.h"21#include "clang/AST/Expr.h"22#include "clang/AST/ExprCXX.h"23#include "clang/AST/ExprObjC.h"24#include "clang/AST/OperationKinds.h"25#include "clang/AST/ParentMap.h"26#include "clang/AST/StmtCXX.h"27#include "clang/AST/StmtObjC.h"28#include "clang/AST/Type.h"29#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"30#include "clang/Analysis/Analyses/CalledOnceCheck.h"31#include "clang/Analysis/Analyses/Consumed.h"32#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h"33#include "clang/Analysis/Analyses/ReachableCode.h"34#include "clang/Analysis/Analyses/ThreadSafety.h"35#include "clang/Analysis/Analyses/UninitializedValues.h"36#include "clang/Analysis/Analyses/UnsafeBufferUsage.h"37#include "clang/Analysis/AnalysisDeclContext.h"38#include "clang/Analysis/CFG.h"39#include "clang/Analysis/CFGStmtMap.h"40#include "clang/Analysis/FlowSensitive/DataflowWorklist.h"41#include "clang/Basic/Diagnostic.h"42#include "clang/Basic/DiagnosticSema.h"43#include "clang/Basic/SourceLocation.h"44#include "clang/Basic/SourceManager.h"45#include "clang/Lex/Preprocessor.h"46#include "clang/Sema/ScopeInfo.h"47#include "clang/Sema/SemaInternal.h"48#include "llvm/ADT/ArrayRef.h"49#include "llvm/ADT/BitVector.h"50#include "llvm/ADT/DenseMap.h"51#include "llvm/ADT/MapVector.h"52#include "llvm/ADT/STLFunctionalExtras.h"53#include "llvm/ADT/SmallVector.h"54#include "llvm/ADT/StringRef.h"55#include "llvm/Support/Debug.h"56#include <algorithm>57#include <deque>58#include <iterator>59#include <optional>60 61using namespace clang;62 63//===----------------------------------------------------------------------===//64// Unreachable code analysis.65//===----------------------------------------------------------------------===//66 67namespace {68 class UnreachableCodeHandler : public reachable_code::Callback {69 Sema &S;70 SourceRange PreviousSilenceableCondVal;71 72 public:73 UnreachableCodeHandler(Sema &s) : S(s) {}74 75 void HandleUnreachable(reachable_code::UnreachableKind UK, SourceLocation L,76 SourceRange SilenceableCondVal, SourceRange R1,77 SourceRange R2, bool HasFallThroughAttr) override {78 // If the diagnosed code is `[[fallthrough]];` and79 // `-Wunreachable-code-fallthrough` is enabled, suppress `code will never80 // be executed` warning to avoid generating diagnostic twice81 if (HasFallThroughAttr &&82 !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr,83 SourceLocation()))84 return;85 86 // Avoid reporting multiple unreachable code diagnostics that are87 // triggered by the same conditional value.88 if (PreviousSilenceableCondVal.isValid() &&89 SilenceableCondVal.isValid() &&90 PreviousSilenceableCondVal == SilenceableCondVal)91 return;92 PreviousSilenceableCondVal = SilenceableCondVal;93 94 unsigned diag = diag::warn_unreachable;95 switch (UK) {96 case reachable_code::UK_Break:97 diag = diag::warn_unreachable_break;98 break;99 case reachable_code::UK_Return:100 diag = diag::warn_unreachable_return;101 break;102 case reachable_code::UK_Loop_Increment:103 diag = diag::warn_unreachable_loop_increment;104 break;105 case reachable_code::UK_Other:106 break;107 }108 109 S.Diag(L, diag) << R1 << R2;110 111 SourceLocation Open = SilenceableCondVal.getBegin();112 if (Open.isValid()) {113 SourceLocation Close = SilenceableCondVal.getEnd();114 Close = S.getLocForEndOfToken(Close);115 if (Close.isValid()) {116 S.Diag(Open, diag::note_unreachable_silence)117 << FixItHint::CreateInsertion(Open, "/* DISABLES CODE */ (")118 << FixItHint::CreateInsertion(Close, ")");119 }120 }121 }122 };123} // anonymous namespace124 125/// CheckUnreachable - Check for unreachable code.126static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC) {127 // As a heuristic prune all diagnostics not in the main file. Currently128 // the majority of warnings in headers are false positives. These129 // are largely caused by configuration state, e.g. preprocessor130 // defined code, etc.131 //132 // Note that this is also a performance optimization. Analyzing133 // headers many times can be expensive.134 if (!S.getSourceManager().isInMainFile(AC.getDecl()->getBeginLoc()))135 return;136 137 UnreachableCodeHandler UC(S);138 reachable_code::FindUnreachableCode(AC, S.getPreprocessor(), UC);139}140 141namespace {142/// Warn on logical operator errors in CFGBuilder143class LogicalErrorHandler : public CFGCallback {144 Sema &S;145 146public:147 LogicalErrorHandler(Sema &S) : S(S) {}148 149 static bool HasMacroID(const Expr *E) {150 if (E->getExprLoc().isMacroID())151 return true;152 153 // Recurse to children.154 for (const Stmt *SubStmt : E->children())155 if (const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt))156 if (HasMacroID(SubExpr))157 return true;158 159 return false;160 }161 162 void logicAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) override {163 if (HasMacroID(B))164 return;165 166 unsigned DiagID = isAlwaysTrue167 ? diag::warn_tautological_negation_or_compare168 : diag::warn_tautological_negation_and_compare;169 SourceRange DiagRange = B->getSourceRange();170 S.Diag(B->getExprLoc(), DiagID) << DiagRange;171 }172 173 void compareAlwaysTrue(const BinaryOperator *B,174 bool isAlwaysTrueOrFalse) override {175 if (HasMacroID(B))176 return;177 178 SourceRange DiagRange = B->getSourceRange();179 S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison)180 << DiagRange << isAlwaysTrueOrFalse;181 }182 183 void compareBitwiseEquality(const BinaryOperator *B,184 bool isAlwaysTrue) override {185 if (HasMacroID(B))186 return;187 188 SourceRange DiagRange = B->getSourceRange();189 S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_always)190 << DiagRange << isAlwaysTrue;191 }192 193 void compareBitwiseOr(const BinaryOperator *B) override {194 if (HasMacroID(B))195 return;196 197 SourceRange DiagRange = B->getSourceRange();198 S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;199 }200 201 static bool hasActiveDiagnostics(DiagnosticsEngine &Diags,202 SourceLocation Loc) {203 return !Diags.isIgnored(diag::warn_tautological_overlap_comparison, Loc) ||204 !Diags.isIgnored(diag::warn_comparison_bitwise_or, Loc) ||205 !Diags.isIgnored(diag::warn_tautological_negation_and_compare, Loc);206 }207};208} // anonymous namespace209 210//===----------------------------------------------------------------------===//211// Check for infinite self-recursion in functions212//===----------------------------------------------------------------------===//213 214// Returns true if the function is called anywhere within the CFGBlock.215// For member functions, the additional condition of being call from the216// this pointer is required.217static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block) {218 // Process all the Stmt's in this block to find any calls to FD.219 for (const auto &B : Block) {220 if (B.getKind() != CFGElement::Statement)221 continue;222 223 const CallExpr *CE = dyn_cast<CallExpr>(B.getAs<CFGStmt>()->getStmt());224 if (!CE || !CE->getCalleeDecl() ||225 CE->getCalleeDecl()->getCanonicalDecl() != FD)226 continue;227 228 // Skip function calls which are qualified with a templated class.229 if (const DeclRefExpr *DRE =230 dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenImpCasts()))231 if (NestedNameSpecifier NNS = DRE->getQualifier();232 NNS.getKind() == NestedNameSpecifier::Kind::Type)233 if (isa_and_nonnull<TemplateSpecializationType>(NNS.getAsType()))234 continue;235 236 const CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(CE);237 if (!MCE || isa<CXXThisExpr>(MCE->getImplicitObjectArgument()) ||238 !MCE->getMethodDecl()->isVirtual())239 return true;240 }241 return false;242}243 244// Returns true if every path from the entry block passes through a call to FD.245static bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg) {246 llvm::SmallPtrSet<CFGBlock *, 16> Visited;247 llvm::SmallVector<CFGBlock *, 16> WorkList;248 // Keep track of whether we found at least one recursive path.249 bool foundRecursion = false;250 251 const unsigned ExitID = cfg->getExit().getBlockID();252 253 // Seed the work list with the entry block.254 WorkList.push_back(&cfg->getEntry());255 256 while (!WorkList.empty()) {257 CFGBlock *Block = WorkList.pop_back_val();258 259 for (auto I = Block->succ_begin(), E = Block->succ_end(); I != E; ++I) {260 if (CFGBlock *SuccBlock = *I) {261 if (!Visited.insert(SuccBlock).second)262 continue;263 264 // Found a path to the exit node without a recursive call.265 if (ExitID == SuccBlock->getBlockID())266 return false;267 268 // If the successor block contains a recursive call, end analysis there.269 if (hasRecursiveCallInPath(FD, *SuccBlock)) {270 foundRecursion = true;271 continue;272 }273 274 WorkList.push_back(SuccBlock);275 }276 }277 }278 return foundRecursion;279}280 281static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,282 const Stmt *Body, AnalysisDeclContext &AC) {283 FD = FD->getCanonicalDecl();284 285 // Only run on non-templated functions and non-templated members of286 // templated classes.287 if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate &&288 FD->getTemplatedKind() != FunctionDecl::TK_MemberSpecialization)289 return;290 291 CFG *cfg = AC.getCFG();292 if (!cfg) return;293 294 // If the exit block is unreachable, skip processing the function.295 if (cfg->getExit().pred_empty())296 return;297 298 // Emit diagnostic if a recursive function call is detected for all paths.299 if (checkForRecursiveFunctionCall(FD, cfg))300 S.Diag(Body->getBeginLoc(), diag::warn_infinite_recursive_function);301}302 303//===----------------------------------------------------------------------===//304// Check for throw in a non-throwing function.305//===----------------------------------------------------------------------===//306 307/// Determine whether an exception thrown by E, unwinding from ThrowBlock,308/// can reach ExitBlock.309static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock,310 CFG *Body) {311 SmallVector<CFGBlock *, 16> Stack;312 llvm::BitVector Queued(Body->getNumBlockIDs());313 314 Stack.push_back(&ThrowBlock);315 Queued[ThrowBlock.getBlockID()] = true;316 317 while (!Stack.empty()) {318 CFGBlock &UnwindBlock = *Stack.pop_back_val();319 320 for (auto &Succ : UnwindBlock.succs()) {321 if (!Succ.isReachable() || Queued[Succ->getBlockID()])322 continue;323 324 if (Succ->getBlockID() == Body->getExit().getBlockID())325 return true;326 327 if (auto *Catch =328 dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {329 QualType Caught = Catch->getCaughtType();330 if (Caught.isNull() || // catch (...) catches everything331 !E->getSubExpr() || // throw; is considered cuaght by any handler332 S.handlerCanCatch(Caught, E->getSubExpr()->getType()))333 // Exception doesn't escape via this path.334 break;335 } else {336 Stack.push_back(Succ);337 Queued[Succ->getBlockID()] = true;338 }339 }340 }341 342 return false;343}344 345static void visitReachableThrows(346 CFG *BodyCFG,347 llvm::function_ref<void(const CXXThrowExpr *, CFGBlock &)> Visit) {348 llvm::BitVector Reachable(BodyCFG->getNumBlockIDs());349 clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(), Reachable);350 for (CFGBlock *B : *BodyCFG) {351 if (!Reachable[B->getBlockID()])352 continue;353 for (CFGElement &E : *B) {354 std::optional<CFGStmt> S = E.getAs<CFGStmt>();355 if (!S)356 continue;357 if (auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))358 Visit(Throw, *B);359 }360 }361}362 363static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc,364 const FunctionDecl *FD) {365 if (!S.getSourceManager().isInSystemHeader(OpLoc) &&366 FD->getTypeSourceInfo()) {367 S.Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;368 if (S.getLangOpts().CPlusPlus11 &&369 (isa<CXXDestructorDecl>(FD) ||370 FD->getDeclName().getCXXOverloadedOperator() == OO_Delete ||371 FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) {372 if (const auto *Ty = FD->getTypeSourceInfo()->getType()->373 getAs<FunctionProtoType>())374 S.Diag(FD->getLocation(), diag::note_throw_in_dtor)375 << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec()376 << FD->getExceptionSpecSourceRange();377 } else378 S.Diag(FD->getLocation(), diag::note_throw_in_function)379 << FD->getExceptionSpecSourceRange();380 }381}382 383static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD,384 AnalysisDeclContext &AC) {385 CFG *BodyCFG = AC.getCFG();386 if (!BodyCFG)387 return;388 if (BodyCFG->getExit().pred_empty())389 return;390 visitReachableThrows(BodyCFG, [&](const CXXThrowExpr *Throw, CFGBlock &Block) {391 if (throwEscapes(S, Throw, Block, BodyCFG))392 EmitDiagForCXXThrowInNonThrowingFunc(S, Throw->getThrowLoc(), FD);393 });394}395 396static bool isNoexcept(const FunctionDecl *FD) {397 const auto *FPT = FD->getType()->castAs<FunctionProtoType>();398 if (FPT->isNothrow() || FD->hasAttr<NoThrowAttr>())399 return true;400 return false;401}402 403/// Checks if the given expression is a reference to a function with404/// 'noreturn' attribute.405static bool isReferenceToNoReturn(const Expr *E) {406 if (auto *DRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))407 if (auto *FD = dyn_cast<FunctionDecl>(DRef->getDecl()))408 return FD->isNoReturn();409 return false;410}411 412/// Checks if the given variable, which is assumed to be a function pointer, is413/// initialized with a function having 'noreturn' attribute.414static bool isInitializedWithNoReturn(const VarDecl *VD) {415 if (const Expr *Init = VD->getInit()) {416 if (auto *ListInit = dyn_cast<InitListExpr>(Init);417 ListInit && ListInit->getNumInits() > 0)418 Init = ListInit->getInit(0);419 return isReferenceToNoReturn(Init);420 }421 return false;422}423 424namespace {425 426/// Looks for statements, that can define value of the given variable.427struct TransferFunctions : public StmtVisitor<TransferFunctions> {428 const VarDecl *Var;429 std::optional<bool> AllValuesAreNoReturn;430 431 TransferFunctions(const VarDecl *VD) : Var(VD) {}432 433 void reset() { AllValuesAreNoReturn = std::nullopt; }434 435 void VisitDeclStmt(DeclStmt *DS) {436 for (auto *DI : DS->decls())437 if (auto *VD = dyn_cast<VarDecl>(DI))438 if (VarDecl *Def = VD->getDefinition())439 if (Def == Var)440 AllValuesAreNoReturn = isInitializedWithNoReturn(Def);441 }442 443 void VisitUnaryOperator(UnaryOperator *UO) {444 if (UO->getOpcode() == UO_AddrOf) {445 if (auto *DRef =446 dyn_cast<DeclRefExpr>(UO->getSubExpr()->IgnoreParenCasts()))447 if (DRef->getDecl() == Var)448 AllValuesAreNoReturn = false;449 }450 }451 452 void VisitBinaryOperator(BinaryOperator *BO) {453 if (BO->getOpcode() == BO_Assign)454 if (auto *DRef = dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParenCasts()))455 if (DRef->getDecl() == Var)456 AllValuesAreNoReturn = isReferenceToNoReturn(BO->getRHS());457 }458 459 void VisitCallExpr(CallExpr *CE) {460 for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); I != E;461 ++I) {462 const Expr *Arg = *I;463 if (Arg->isGLValue() && !Arg->getType().isConstQualified())464 if (auto *DRef = dyn_cast<DeclRefExpr>(Arg->IgnoreParenCasts()))465 if (auto VD = dyn_cast<VarDecl>(DRef->getDecl()))466 if (VD->getDefinition() == Var)467 AllValuesAreNoReturn = false;468 }469 }470};471} // namespace472 473// Checks if all possible values of the given variable are functions with474// 'noreturn' attribute.475static bool areAllValuesNoReturn(const VarDecl *VD, const CFGBlock &VarBlk,476 AnalysisDeclContext &AC) {477 // The set of possible values of a constant variable is determined by478 // its initializer, unless it is a function parameter.479 if (!isa<ParmVarDecl>(VD) && VD->getType().isConstant(AC.getASTContext())) {480 if (const VarDecl *Def = VD->getDefinition())481 return isInitializedWithNoReturn(Def);482 return false;483 }484 485 // In multithreaded environment the value of a global variable may be changed486 // asynchronously.487 if (!VD->getDeclContext()->isFunctionOrMethod())488 return false;489 490 // Check the condition "all values are noreturn". It is satisfied if the491 // variable is set to "noreturn" value in the current block or all its492 // predecessors satisfies the condition.493 using MapTy = llvm::DenseMap<const CFGBlock *, std::optional<bool>>;494 using ValueTy = MapTy::value_type;495 MapTy BlocksToCheck;496 BlocksToCheck[&VarBlk] = std::nullopt;497 const auto BlockSatisfiesCondition = [](ValueTy Item) {498 return Item.getSecond().value_or(false);499 };500 501 TransferFunctions TF(VD);502 BackwardDataflowWorklist Worklist(*AC.getCFG(), AC);503 llvm::DenseSet<const CFGBlock *> Visited;504 Worklist.enqueueBlock(&VarBlk);505 while (const CFGBlock *B = Worklist.dequeue()) {506 if (Visited.contains(B))507 continue;508 Visited.insert(B);509 // First check the current block.510 for (CFGBlock::const_reverse_iterator ri = B->rbegin(), re = B->rend();511 ri != re; ++ri) {512 if (std::optional<CFGStmt> cs = ri->getAs<CFGStmt>()) {513 const Stmt *S = cs->getStmt();514 TF.reset();515 TF.Visit(const_cast<Stmt *>(S));516 if (TF.AllValuesAreNoReturn) {517 if (!TF.AllValuesAreNoReturn.value())518 return false;519 BlocksToCheck[B] = true;520 break;521 }522 }523 }524 525 // If all checked blocks satisfy the condition, the check is finished.526 if (llvm::all_of(BlocksToCheck, BlockSatisfiesCondition))527 return true;528 529 // If this block does not contain the variable definition, check530 // its predecessors.531 if (!BlocksToCheck[B]) {532 Worklist.enqueuePredecessors(B);533 BlocksToCheck.erase(B);534 for (const auto &PredBlk : B->preds())535 if (!BlocksToCheck.contains(PredBlk))536 BlocksToCheck[PredBlk] = std::nullopt;537 }538 }539 540 return false;541}542 543//===----------------------------------------------------------------------===//544// Check for missing return value.545//===----------------------------------------------------------------------===//546 547enum ControlFlowKind {548 UnknownFallThrough,549 NeverFallThrough,550 MaybeFallThrough,551 AlwaysFallThrough,552 NeverFallThroughOrReturn553};554 555/// CheckFallThrough - Check that we don't fall off the end of a556/// Statement that should return a value.557///558/// \returns AlwaysFallThrough iff we always fall off the end of the statement,559/// MaybeFallThrough iff we might or might not fall off the end,560/// NeverFallThroughOrReturn iff we never fall off the end of the statement or561/// return. We assume NeverFallThrough iff we never fall off the end of the562/// statement but we may return. We assume that functions not marked noreturn563/// will return.564static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {565 CFG *cfg = AC.getCFG();566 if (!cfg) return UnknownFallThrough;567 568 // The CFG leaves in dead things, and we don't want the dead code paths to569 // confuse us, so we mark all live things first.570 llvm::BitVector live(cfg->getNumBlockIDs());571 unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(),572 live);573 574 bool AddEHEdges = AC.getAddEHEdges();575 if (!AddEHEdges && count != cfg->getNumBlockIDs())576 // When there are things remaining dead, and we didn't add EH edges577 // from CallExprs to the catch clauses, we have to go back and578 // mark them as live.579 for (const auto *B : *cfg) {580 if (!live[B->getBlockID()]) {581 if (B->preds().empty()) {582 const Stmt *Term = B->getTerminatorStmt();583 if (isa_and_nonnull<CXXTryStmt>(Term))584 // When not adding EH edges from calls, catch clauses585 // can otherwise seem dead. Avoid noting them as dead.586 count += reachable_code::ScanReachableFromBlock(B, live);587 continue;588 }589 }590 }591 592 // Now we know what is live, we check the live precessors of the exit block593 // and look for fall through paths, being careful to ignore normal returns,594 // and exceptional paths.595 bool HasLiveReturn = false;596 bool HasFakeEdge = false;597 bool HasPlainEdge = false;598 bool HasAbnormalEdge = false;599 600 // Ignore default cases that aren't likely to be reachable because all601 // enums in a switch(X) have explicit case statements.602 CFGBlock::FilterOptions FO;603 FO.IgnoreDefaultsWithCoveredEnums = 1;604 605 for (CFGBlock::filtered_pred_iterator I =606 cfg->getExit().filtered_pred_start_end(FO);607 I.hasMore(); ++I) {608 const CFGBlock &B = **I;609 if (!live[B.getBlockID()])610 continue;611 612 // Skip blocks which contain an element marked as no-return. They don't613 // represent actually viable edges into the exit block, so mark them as614 // abnormal.615 if (B.hasNoReturnElement()) {616 HasAbnormalEdge = true;617 continue;618 }619 620 // Destructors can appear after the 'return' in the CFG. This is621 // normal. We need to look pass the destructors for the return622 // statement (if it exists).623 CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend();624 625 for ( ; ri != re ; ++ri)626 if (ri->getAs<CFGStmt>())627 break;628 629 // No more CFGElements in the block?630 if (ri == re) {631 const Stmt *Term = B.getTerminatorStmt();632 if (Term && (isa<CXXTryStmt>(Term) || isa<ObjCAtTryStmt>(Term))) {633 HasAbnormalEdge = true;634 continue;635 }636 // A labeled empty statement, or the entry block...637 HasPlainEdge = true;638 continue;639 }640 641 CFGStmt CS = ri->castAs<CFGStmt>();642 const Stmt *S = CS.getStmt();643 if (isa<ReturnStmt>(S) || isa<CoreturnStmt>(S)) {644 HasLiveReturn = true;645 continue;646 }647 if (isa<ObjCAtThrowStmt>(S)) {648 HasFakeEdge = true;649 continue;650 }651 if (isa<CXXThrowExpr>(S)) {652 HasFakeEdge = true;653 continue;654 }655 if (isa<MSAsmStmt>(S)) {656 // TODO: Verify this is correct.657 HasFakeEdge = true;658 HasLiveReturn = true;659 continue;660 }661 if (isa<CXXTryStmt>(S)) {662 HasAbnormalEdge = true;663 continue;664 }665 if (!llvm::is_contained(B.succs(), &cfg->getExit())) {666 HasAbnormalEdge = true;667 continue;668 }669 if (auto *Call = dyn_cast<CallExpr>(S)) {670 const Expr *Callee = Call->getCallee();671 if (Callee->getType()->isPointerType())672 if (auto *DeclRef =673 dyn_cast<DeclRefExpr>(Callee->IgnoreParenImpCasts()))674 if (auto *VD = dyn_cast<VarDecl>(DeclRef->getDecl()))675 if (areAllValuesNoReturn(VD, B, AC)) {676 HasAbnormalEdge = true;677 continue;678 }679 }680 681 HasPlainEdge = true;682 }683 if (!HasPlainEdge) {684 if (HasLiveReturn)685 return NeverFallThrough;686 return NeverFallThroughOrReturn;687 }688 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)689 return MaybeFallThrough;690 // This says AlwaysFallThrough for calls to functions that are not marked691 // noreturn, that don't return. If people would like this warning to be more692 // accurate, such functions should be marked as noreturn.693 return AlwaysFallThrough;694}695 696namespace {697 698struct CheckFallThroughDiagnostics {699 unsigned diag_FallThrough_HasNoReturn = 0;700 unsigned diag_FallThrough_ReturnsNonVoid = 0;701 unsigned diag_NeverFallThroughOrReturn = 0;702 unsigned FunKind; // TODO: use diag::FalloffFunctionKind703 SourceLocation FuncLoc;704 705 static CheckFallThroughDiagnostics MakeForFunction(Sema &S,706 const Decl *Func) {707 CheckFallThroughDiagnostics D;708 D.FuncLoc = Func->getLocation();709 D.diag_FallThrough_HasNoReturn = diag::warn_noreturn_has_return_expr;710 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;711 712 // Don't suggest that virtual functions be marked "noreturn", since they713 // might be overridden by non-noreturn functions.714 bool isVirtualMethod = false;715 if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func))716 isVirtualMethod = Method->isVirtual();717 718 // Don't suggest that template instantiations be marked "noreturn"719 bool isTemplateInstantiation = false;720 if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func)) {721 isTemplateInstantiation = Function->isTemplateInstantiation();722 if (!S.getLangOpts().CPlusPlus && !S.getLangOpts().C99 &&723 Function->isMain()) {724 D.diag_FallThrough_ReturnsNonVoid = diag::ext_main_no_return;725 }726 }727 728 if (!isVirtualMethod && !isTemplateInstantiation)729 D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function;730 731 D.FunKind = diag::FalloffFunctionKind::Function;732 return D;733 }734 735 static CheckFallThroughDiagnostics MakeForCoroutine(const Decl *Func) {736 CheckFallThroughDiagnostics D;737 D.FuncLoc = Func->getLocation();738 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;739 D.FunKind = diag::FalloffFunctionKind::Coroutine;740 return D;741 }742 743 static CheckFallThroughDiagnostics MakeForBlock() {744 CheckFallThroughDiagnostics D;745 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;746 D.diag_FallThrough_ReturnsNonVoid = diag::err_falloff_nonvoid;747 D.FunKind = diag::FalloffFunctionKind::Block;748 return D;749 }750 751 static CheckFallThroughDiagnostics MakeForLambda() {752 CheckFallThroughDiagnostics D;753 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;754 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;755 D.FunKind = diag::FalloffFunctionKind::Lambda;756 return D;757 }758 759 bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid,760 bool HasNoReturn) const {761 if (FunKind == diag::FalloffFunctionKind::Function) {762 return (ReturnsVoid ||763 D.isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&764 (!HasNoReturn ||765 D.isIgnored(diag::warn_noreturn_has_return_expr, FuncLoc)) &&766 (!ReturnsVoid ||767 D.isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));768 }769 if (FunKind == diag::FalloffFunctionKind::Coroutine) {770 return (ReturnsVoid ||771 D.isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&772 (!HasNoReturn);773 }774 // For blocks / lambdas.775 return ReturnsVoid && !HasNoReturn;776 }777};778 779} // anonymous namespace780 781/// CheckFallThroughForBody - Check that we don't fall off the end of a782/// function that should return a value. Check that we don't fall off the end783/// of a noreturn function. We assume that functions and blocks not marked784/// noreturn will return.785static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,786 QualType BlockType,787 const CheckFallThroughDiagnostics &CD,788 AnalysisDeclContext &AC) {789 790 bool ReturnsVoid = false;791 bool HasNoReturn = false;792 793 if (const auto *FD = dyn_cast<FunctionDecl>(D)) {794 if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))795 ReturnsVoid = CBody->getFallthroughHandler() != nullptr;796 else797 ReturnsVoid = FD->getReturnType()->isVoidType();798 HasNoReturn = FD->isNoReturn() || FD->hasAttr<InferredNoReturnAttr>();799 }800 else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {801 ReturnsVoid = MD->getReturnType()->isVoidType();802 HasNoReturn = MD->hasAttr<NoReturnAttr>();803 }804 else if (isa<BlockDecl>(D)) {805 if (const FunctionType *FT =806 BlockType->getPointeeType()->getAs<FunctionType>()) {807 if (FT->getReturnType()->isVoidType())808 ReturnsVoid = true;809 if (FT->getNoReturnAttr())810 HasNoReturn = true;811 }812 }813 814 DiagnosticsEngine &Diags = S.getDiagnostics();815 816 // Short circuit for compilation speed.817 if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))818 return;819 SourceLocation LBrace = Body->getBeginLoc(), RBrace = Body->getEndLoc();820 821 // cpu_dispatch functions permit empty function bodies for ICC compatibility.822 if (D->getAsFunction() && D->getAsFunction()->isCPUDispatchMultiVersion())823 return;824 825 // Either in a function body compound statement, or a function-try-block.826 switch (int FallThroughType = CheckFallThrough(AC)) {827 case UnknownFallThrough:828 break;829 830 case MaybeFallThrough:831 case AlwaysFallThrough:832 if (HasNoReturn) {833 if (CD.diag_FallThrough_HasNoReturn)834 S.Diag(RBrace, CD.diag_FallThrough_HasNoReturn) << CD.FunKind;835 } else if (!ReturnsVoid && CD.diag_FallThrough_ReturnsNonVoid) {836 // If the final statement is a call to an always-throwing function,837 // don't warn about the fall-through.838 if (D->getAsFunction()) {839 if (const auto *CS = dyn_cast<CompoundStmt>(Body);840 CS && !CS->body_empty()) {841 const Stmt *LastStmt = CS->body_back();842 // Unwrap ExprWithCleanups if necessary.843 if (const auto *EWC = dyn_cast<ExprWithCleanups>(LastStmt)) {844 LastStmt = EWC->getSubExpr();845 }846 if (const auto *CE = dyn_cast<CallExpr>(LastStmt)) {847 if (const FunctionDecl *Callee = CE->getDirectCallee();848 Callee && Callee->hasAttr<InferredNoReturnAttr>()) {849 return; // Don't warn about fall-through.850 }851 }852 // Direct throw.853 if (isa<CXXThrowExpr>(LastStmt)) {854 return; // Don't warn about fall-through.855 }856 }857 }858 bool NotInAllControlPaths = FallThroughType == MaybeFallThrough;859 S.Diag(RBrace, CD.diag_FallThrough_ReturnsNonVoid)860 << CD.FunKind << NotInAllControlPaths;861 }862 break;863 case NeverFallThroughOrReturn:864 if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {865 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {866 S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;867 } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {868 S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;869 } else {870 S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn);871 }872 }873 break;874 case NeverFallThrough:875 break;876 }877}878 879//===----------------------------------------------------------------------===//880// -Wuninitialized881//===----------------------------------------------------------------------===//882 883namespace {884/// ContainsReference - A visitor class to search for references to885/// a particular declaration (the needle) within any evaluated component of an886/// expression (recursively).887class ContainsReference : public ConstEvaluatedExprVisitor<ContainsReference> {888 bool FoundReference;889 const DeclRefExpr *Needle;890 891public:892 typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited;893 894 ContainsReference(ASTContext &Context, const DeclRefExpr *Needle)895 : Inherited(Context), FoundReference(false), Needle(Needle) {}896 897 void VisitExpr(const Expr *E) {898 // Stop evaluating if we already have a reference.899 if (FoundReference)900 return;901 902 Inherited::VisitExpr(E);903 }904 905 void VisitDeclRefExpr(const DeclRefExpr *E) {906 if (E == Needle)907 FoundReference = true;908 else909 Inherited::VisitDeclRefExpr(E);910 }911 912 bool doesContainReference() const { return FoundReference; }913};914} // anonymous namespace915 916static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {917 QualType VariableTy = VD->getType().getCanonicalType();918 if (VariableTy->isBlockPointerType() &&919 !VD->hasAttr<BlocksAttr>()) {920 S.Diag(VD->getLocation(), diag::note_block_var_fixit_add_initialization)921 << VD->getDeclName()922 << FixItHint::CreateInsertion(VD->getLocation(), "__block ");923 return true;924 }925 926 // Don't issue a fixit if there is already an initializer.927 if (VD->getInit())928 return false;929 930 // Don't suggest a fixit inside macros.931 if (VD->getEndLoc().isMacroID())932 return false;933 934 SourceLocation Loc = S.getLocForEndOfToken(VD->getEndLoc());935 936 // Suggest possible initialization (if any).937 std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc);938 if (Init.empty())939 return false;940 941 S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName()942 << FixItHint::CreateInsertion(Loc, Init);943 return true;944}945 946/// Create a fixit to remove an if-like statement, on the assumption that its947/// condition is CondVal.948static void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then,949 const Stmt *Else, bool CondVal,950 FixItHint &Fixit1, FixItHint &Fixit2) {951 if (CondVal) {952 // If condition is always true, remove all but the 'then'.953 Fixit1 = FixItHint::CreateRemoval(954 CharSourceRange::getCharRange(If->getBeginLoc(), Then->getBeginLoc()));955 if (Else) {956 SourceLocation ElseKwLoc = S.getLocForEndOfToken(Then->getEndLoc());957 Fixit2 =958 FixItHint::CreateRemoval(SourceRange(ElseKwLoc, Else->getEndLoc()));959 }960 } else {961 // If condition is always false, remove all but the 'else'.962 if (Else)963 Fixit1 = FixItHint::CreateRemoval(CharSourceRange::getCharRange(964 If->getBeginLoc(), Else->getBeginLoc()));965 else966 Fixit1 = FixItHint::CreateRemoval(If->getSourceRange());967 }968}969 970/// DiagUninitUse -- Helper function to produce a diagnostic for an971/// uninitialized use of a variable.972static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,973 bool IsCapturedByBlock) {974 bool Diagnosed = false;975 976 switch (Use.getKind()) {977 case UninitUse::Always:978 S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_var)979 << VD->getDeclName() << IsCapturedByBlock980 << Use.getUser()->getSourceRange();981 return;982 983 case UninitUse::AfterDecl:984 case UninitUse::AfterCall:985 S.Diag(VD->getLocation(), diag::warn_sometimes_uninit_var)986 << VD->getDeclName() << IsCapturedByBlock987 << (Use.getKind() == UninitUse::AfterDecl ? 4 : 5)988 << VD->getLexicalDeclContext() << VD->getSourceRange();989 S.Diag(Use.getUser()->getBeginLoc(), diag::note_uninit_var_use)990 << IsCapturedByBlock << Use.getUser()->getSourceRange();991 return;992 993 case UninitUse::Maybe:994 case UninitUse::Sometimes:995 // Carry on to report sometimes-uninitialized branches, if possible,996 // or a 'may be used uninitialized' diagnostic otherwise.997 break;998 }999 1000 // Diagnose each branch which leads to a sometimes-uninitialized use.1001 for (UninitUse::branch_iterator I = Use.branch_begin(), E = Use.branch_end();1002 I != E; ++I) {1003 assert(Use.getKind() == UninitUse::Sometimes);1004 1005 const Expr *User = Use.getUser();1006 const Stmt *Term = I->Terminator;1007 1008 // Information used when building the diagnostic.1009 unsigned DiagKind;1010 StringRef Str;1011 SourceRange Range;1012 1013 // FixIts to suppress the diagnostic by removing the dead condition.1014 // For all binary terminators, branch 0 is taken if the condition is true,1015 // and branch 1 is taken if the condition is false.1016 int RemoveDiagKind = -1;1017 const char *FixitStr =1018 S.getLangOpts().CPlusPlus ? (I->Output ? "true" : "false")1019 : (I->Output ? "1" : "0");1020 FixItHint Fixit1, Fixit2;1021 1022 switch (Term ? Term->getStmtClass() : Stmt::DeclStmtClass) {1023 default:1024 // Don't know how to report this. Just fall back to 'may be used1025 // uninitialized'. FIXME: Can this happen?1026 continue;1027 1028 // "condition is true / condition is false".1029 case Stmt::IfStmtClass: {1030 const IfStmt *IS = cast<IfStmt>(Term);1031 DiagKind = 0;1032 Str = "if";1033 Range = IS->getCond()->getSourceRange();1034 RemoveDiagKind = 0;1035 CreateIfFixit(S, IS, IS->getThen(), IS->getElse(),1036 I->Output, Fixit1, Fixit2);1037 break;1038 }1039 case Stmt::ConditionalOperatorClass: {1040 const ConditionalOperator *CO = cast<ConditionalOperator>(Term);1041 DiagKind = 0;1042 Str = "?:";1043 Range = CO->getCond()->getSourceRange();1044 RemoveDiagKind = 0;1045 CreateIfFixit(S, CO, CO->getTrueExpr(), CO->getFalseExpr(),1046 I->Output, Fixit1, Fixit2);1047 break;1048 }1049 case Stmt::BinaryOperatorClass: {1050 const BinaryOperator *BO = cast<BinaryOperator>(Term);1051 if (!BO->isLogicalOp())1052 continue;1053 DiagKind = 0;1054 Str = BO->getOpcodeStr();1055 Range = BO->getLHS()->getSourceRange();1056 RemoveDiagKind = 0;1057 if ((BO->getOpcode() == BO_LAnd && I->Output) ||1058 (BO->getOpcode() == BO_LOr && !I->Output))1059 // true && y -> y, false || y -> y.1060 Fixit1 = FixItHint::CreateRemoval(1061 SourceRange(BO->getBeginLoc(), BO->getOperatorLoc()));1062 else1063 // false && y -> false, true || y -> true.1064 Fixit1 = FixItHint::CreateReplacement(BO->getSourceRange(), FixitStr);1065 break;1066 }1067 1068 // "loop is entered / loop is exited".1069 case Stmt::WhileStmtClass:1070 DiagKind = 1;1071 Str = "while";1072 Range = cast<WhileStmt>(Term)->getCond()->getSourceRange();1073 RemoveDiagKind = 1;1074 Fixit1 = FixItHint::CreateReplacement(Range, FixitStr);1075 break;1076 case Stmt::ForStmtClass:1077 DiagKind = 1;1078 Str = "for";1079 Range = cast<ForStmt>(Term)->getCond()->getSourceRange();1080 RemoveDiagKind = 1;1081 if (I->Output)1082 Fixit1 = FixItHint::CreateRemoval(Range);1083 else1084 Fixit1 = FixItHint::CreateReplacement(Range, FixitStr);1085 break;1086 case Stmt::CXXForRangeStmtClass:1087 if (I->Output == 1) {1088 // The use occurs if a range-based for loop's body never executes.1089 // That may be impossible, and there's no syntactic fix for this,1090 // so treat it as a 'may be uninitialized' case.1091 continue;1092 }1093 DiagKind = 1;1094 Str = "for";1095 Range = cast<CXXForRangeStmt>(Term)->getRangeInit()->getSourceRange();1096 break;1097 1098 // "condition is true / loop is exited".1099 case Stmt::DoStmtClass:1100 DiagKind = 2;1101 Str = "do";1102 Range = cast<DoStmt>(Term)->getCond()->getSourceRange();1103 RemoveDiagKind = 1;1104 Fixit1 = FixItHint::CreateReplacement(Range, FixitStr);1105 break;1106 1107 // "switch case is taken".1108 case Stmt::CaseStmtClass:1109 DiagKind = 3;1110 Str = "case";1111 Range = cast<CaseStmt>(Term)->getLHS()->getSourceRange();1112 break;1113 case Stmt::DefaultStmtClass:1114 DiagKind = 3;1115 Str = "default";1116 Range = cast<DefaultStmt>(Term)->getDefaultLoc();1117 break;1118 }1119 1120 S.Diag(Range.getBegin(), diag::warn_sometimes_uninit_var)1121 << VD->getDeclName() << IsCapturedByBlock << DiagKind1122 << Str << I->Output << Range;1123 S.Diag(User->getBeginLoc(), diag::note_uninit_var_use)1124 << IsCapturedByBlock << User->getSourceRange();1125 if (RemoveDiagKind != -1)1126 S.Diag(Fixit1.RemoveRange.getBegin(), diag::note_uninit_fixit_remove_cond)1127 << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;1128 1129 Diagnosed = true;1130 }1131 1132 if (!Diagnosed)1133 S.Diag(Use.getUser()->getBeginLoc(), diag::warn_maybe_uninit_var)1134 << VD->getDeclName() << IsCapturedByBlock1135 << Use.getUser()->getSourceRange();1136}1137 1138/// Diagnose uninitialized const reference usages.1139static bool DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD,1140 const UninitUse &Use) {1141 S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_const_reference)1142 << VD->getDeclName() << Use.getUser()->getSourceRange();1143 return !S.getDiagnostics().isLastDiagnosticIgnored();1144}1145 1146/// Diagnose uninitialized const pointer usages.1147static bool DiagnoseUninitializedConstPtrUse(Sema &S, const VarDecl *VD,1148 const UninitUse &Use) {1149 S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_const_pointer)1150 << VD->getDeclName() << Use.getUser()->getSourceRange();1151 return !S.getDiagnostics().isLastDiagnosticIgnored();1152}1153 1154/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an1155/// uninitialized variable. This manages the different forms of diagnostic1156/// emitted for particular types of uses. Returns true if the use was diagnosed1157/// as a warning. If a particular use is one we omit warnings for, returns1158/// false.1159static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,1160 const UninitUse &Use,1161 bool alwaysReportSelfInit = false) {1162 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Use.getUser())) {1163 // Inspect the initializer of the variable declaration which is1164 // being referenced prior to its initialization. We emit1165 // specialized diagnostics for self-initialization, and we1166 // specifically avoid warning about self references which take the1167 // form of:1168 //1169 // int x = x;1170 //1171 // This is used to indicate to GCC that 'x' is intentionally left1172 // uninitialized. Proven code paths which access 'x' in1173 // an uninitialized state after this will still warn.1174 if (const Expr *Initializer = VD->getInit()) {1175 if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts())1176 return false;1177 1178 ContainsReference CR(S.Context, DRE);1179 CR.Visit(Initializer);1180 if (CR.doesContainReference()) {1181 S.Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)1182 << VD->getDeclName() << VD->getLocation() << DRE->getSourceRange();1183 return !S.getDiagnostics().isLastDiagnosticIgnored();1184 }1185 }1186 1187 DiagUninitUse(S, VD, Use, false);1188 } else {1189 const BlockExpr *BE = cast<BlockExpr>(Use.getUser());1190 if (VD->getType()->isBlockPointerType() && !VD->hasAttr<BlocksAttr>())1191 S.Diag(BE->getBeginLoc(),1192 diag::warn_uninit_byref_blockvar_captured_by_block)1193 << VD->getDeclName()1194 << VD->getType().getQualifiers().hasObjCLifetime();1195 else1196 DiagUninitUse(S, VD, Use, true);1197 }1198 1199 // Report where the variable was declared when the use wasn't within1200 // the initializer of that declaration & we didn't already suggest1201 // an initialization fixit.1202 if (!SuggestInitializationFixit(S, VD))1203 S.Diag(VD->getBeginLoc(), diag::note_var_declared_here)1204 << VD->getDeclName();1205 1206 return !S.getDiagnostics().isLastDiagnosticIgnored();1207}1208 1209namespace {1210class FallthroughMapper : public DynamicRecursiveASTVisitor {1211public:1212 FallthroughMapper(Sema &S) : FoundSwitchStatements(false), S(S) {1213 ShouldWalkTypesOfTypeLocs = false;1214 }1215 1216 bool foundSwitchStatements() const { return FoundSwitchStatements; }1217 1218 void markFallthroughVisited(const AttributedStmt *Stmt) {1219 bool Found = FallthroughStmts.erase(Stmt);1220 assert(Found);1221 (void)Found;1222 }1223 1224 typedef llvm::SmallPtrSet<const AttributedStmt *, 8> AttrStmts;1225 1226 const AttrStmts &getFallthroughStmts() const { return FallthroughStmts; }1227 1228 void fillReachableBlocks(CFG *Cfg) {1229 assert(ReachableBlocks.empty() && "ReachableBlocks already filled");1230 std::deque<const CFGBlock *> BlockQueue;1231 1232 ReachableBlocks.insert(&Cfg->getEntry());1233 BlockQueue.push_back(&Cfg->getEntry());1234 // Mark all case blocks reachable to avoid problems with switching on1235 // constants, covered enums, etc.1236 // These blocks can contain fall-through annotations, and we don't want to1237 // issue a warn_fallthrough_attr_unreachable for them.1238 for (const auto *B : *Cfg) {1239 const Stmt *L = B->getLabel();1240 if (isa_and_nonnull<SwitchCase>(L) && ReachableBlocks.insert(B).second)1241 BlockQueue.push_back(B);1242 }1243 1244 while (!BlockQueue.empty()) {1245 const CFGBlock *P = BlockQueue.front();1246 BlockQueue.pop_front();1247 for (const CFGBlock *B : P->succs()) {1248 if (B && ReachableBlocks.insert(B).second)1249 BlockQueue.push_back(B);1250 }1251 }1252 }1253 1254 bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt,1255 bool IsTemplateInstantiation) {1256 assert(!ReachableBlocks.empty() && "ReachableBlocks empty");1257 1258 int UnannotatedCnt = 0;1259 AnnotatedCnt = 0;1260 1261 std::deque<const CFGBlock *> BlockQueue(B.pred_begin(), B.pred_end());1262 while (!BlockQueue.empty()) {1263 const CFGBlock *P = BlockQueue.front();1264 BlockQueue.pop_front();1265 if (!P)1266 continue;1267 1268 const Stmt *Term = P->getTerminatorStmt();1269 if (isa_and_nonnull<SwitchStmt>(Term))1270 continue; // Switch statement, good.1271 1272 const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->getLabel());1273 if (SW && SW->getSubStmt() == B.getLabel() && P->begin() == P->end())1274 continue; // Previous case label has no statements, good.1275 1276 const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->getLabel());1277 if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end())1278 continue; // Case label is preceded with a normal label, good.1279 1280 if (!ReachableBlocks.count(P)) {1281 for (const CFGElement &Elem : llvm::reverse(*P)) {1282 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) {1283 if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {1284 // Don't issue a warning for an unreachable fallthrough1285 // attribute in template instantiations as it may not be1286 // unreachable in all instantiations of the template.1287 if (!IsTemplateInstantiation)1288 S.Diag(AS->getBeginLoc(),1289 diag::warn_unreachable_fallthrough_attr);1290 markFallthroughVisited(AS);1291 ++AnnotatedCnt;1292 break;1293 }1294 // Don't care about other unreachable statements.1295 }1296 }1297 // If there are no unreachable statements, this may be a special1298 // case in CFG:1299 // case X: {1300 // A a; // A has a destructor.1301 // break;1302 // }1303 // // <<<< This place is represented by a 'hanging' CFG block.1304 // case Y:1305 continue;1306 }1307 1308 const Stmt *LastStmt = getLastStmt(*P);1309 if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {1310 markFallthroughVisited(AS);1311 ++AnnotatedCnt;1312 continue; // Fallthrough annotation, good.1313 }1314 1315 if (!LastStmt) { // This block contains no executable statements.1316 // Traverse its predecessors.1317 std::copy(P->pred_begin(), P->pred_end(),1318 std::back_inserter(BlockQueue));1319 continue;1320 }1321 1322 ++UnannotatedCnt;1323 }1324 return !!UnannotatedCnt;1325 }1326 1327 bool VisitAttributedStmt(AttributedStmt *S) override {1328 if (asFallThroughAttr(S))1329 FallthroughStmts.insert(S);1330 return true;1331 }1332 1333 bool VisitSwitchStmt(SwitchStmt *S) override {1334 FoundSwitchStatements = true;1335 return true;1336 }1337 1338 // We don't want to traverse local type declarations. We analyze their1339 // methods separately.1340 bool TraverseDecl(Decl *D) override { return true; }1341 1342 // We analyze lambda bodies separately. Skip them here.1343 bool TraverseLambdaExpr(LambdaExpr *LE) override {1344 // Traverse the captures, but not the body.1345 for (const auto C : zip(LE->captures(), LE->capture_inits()))1346 TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C));1347 return true;1348 }1349 1350 private:1351 1352 static const AttributedStmt *asFallThroughAttr(const Stmt *S) {1353 if (const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {1354 if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs()))1355 return AS;1356 }1357 return nullptr;1358 }1359 1360 static const Stmt *getLastStmt(const CFGBlock &B) {1361 if (const Stmt *Term = B.getTerminatorStmt())1362 return Term;1363 for (const CFGElement &Elem : llvm::reverse(B))1364 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())1365 return CS->getStmt();1366 // Workaround to detect a statement thrown out by CFGBuilder:1367 // case X: {} case Y:1368 // case X: ; case Y:1369 if (const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.getLabel()))1370 if (!isa<SwitchCase>(SW->getSubStmt()))1371 return SW->getSubStmt();1372 1373 return nullptr;1374 }1375 1376 bool FoundSwitchStatements;1377 AttrStmts FallthroughStmts;1378 Sema &S;1379 llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;1380};1381} // anonymous namespace1382 1383static StringRef getFallthroughAttrSpelling(Preprocessor &PP,1384 SourceLocation Loc) {1385 TokenValue FallthroughTokens[] = {1386 tok::l_square, tok::l_square,1387 PP.getIdentifierInfo("fallthrough"),1388 tok::r_square, tok::r_square1389 };1390 1391 TokenValue ClangFallthroughTokens[] = {1392 tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"),1393 tok::coloncolon, PP.getIdentifierInfo("fallthrough"),1394 tok::r_square, tok::r_square1395 };1396 1397 bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17 && !PP.getLangOpts().C23;1398 1399 StringRef MacroName;1400 if (PreferClangAttr)1401 MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens);1402 if (MacroName.empty())1403 MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens);1404 if (MacroName.empty() && !PreferClangAttr)1405 MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens);1406 if (MacroName.empty()) {1407 if (!PreferClangAttr)1408 MacroName = "[[fallthrough]]";1409 else if (PP.getLangOpts().CPlusPlus)1410 MacroName = "[[clang::fallthrough]]";1411 else1412 MacroName = "__attribute__((fallthrough))";1413 }1414 return MacroName;1415}1416 1417static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,1418 bool PerFunction) {1419 FallthroughMapper FM(S);1420 FM.TraverseStmt(AC.getBody());1421 1422 if (!FM.foundSwitchStatements())1423 return;1424 1425 if (PerFunction && FM.getFallthroughStmts().empty())1426 return;1427 1428 CFG *Cfg = AC.getCFG();1429 1430 if (!Cfg)1431 return;1432 1433 FM.fillReachableBlocks(Cfg);1434 1435 for (const CFGBlock *B : llvm::reverse(*Cfg)) {1436 const Stmt *Label = B->getLabel();1437 1438 if (!isa_and_nonnull<SwitchCase>(Label))1439 continue;1440 1441 int AnnotatedCnt;1442 1443 bool IsTemplateInstantiation = false;1444 if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(AC.getDecl()))1445 IsTemplateInstantiation = Function->isTemplateInstantiation();1446 if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,1447 IsTemplateInstantiation))1448 continue;1449 1450 S.Diag(Label->getBeginLoc(),1451 PerFunction ? diag::warn_unannotated_fallthrough_per_function1452 : diag::warn_unannotated_fallthrough);1453 1454 if (!AnnotatedCnt) {1455 SourceLocation L = Label->getBeginLoc();1456 if (L.isMacroID())1457 continue;1458 1459 const Stmt *Term = B->getTerminatorStmt();1460 // Skip empty cases.1461 while (B->empty() && !Term && B->succ_size() == 1) {1462 B = *B->succ_begin();1463 Term = B->getTerminatorStmt();1464 }1465 if (!(B->empty() && isa_and_nonnull<BreakStmt>(Term))) {1466 Preprocessor &PP = S.getPreprocessor();1467 StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L);1468 SmallString<64> TextToInsert(AnnotationSpelling);1469 TextToInsert += "; ";1470 S.Diag(L, diag::note_insert_fallthrough_fixit)1471 << AnnotationSpelling1472 << FixItHint::CreateInsertion(L, TextToInsert);1473 }1474 S.Diag(L, diag::note_insert_break_fixit)1475 << FixItHint::CreateInsertion(L, "break; ");1476 }1477 }1478 1479 for (const auto *F : FM.getFallthroughStmts())1480 S.Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement);1481}1482 1483static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM,1484 const Stmt *S) {1485 assert(S);1486 1487 do {1488 switch (S->getStmtClass()) {1489 case Stmt::ForStmtClass:1490 case Stmt::WhileStmtClass:1491 case Stmt::CXXForRangeStmtClass:1492 case Stmt::ObjCForCollectionStmtClass:1493 return true;1494 case Stmt::DoStmtClass: {1495 Expr::EvalResult Result;1496 if (!cast<DoStmt>(S)->getCond()->EvaluateAsInt(Result, Ctx))1497 return true;1498 return Result.Val.getInt().getBoolValue();1499 }1500 default:1501 break;1502 }1503 } while ((S = PM.getParent(S)));1504 1505 return false;1506}1507 1508static void diagnoseRepeatedUseOfWeak(Sema &S,1509 const sema::FunctionScopeInfo *CurFn,1510 const Decl *D,1511 const ParentMap &PM) {1512 typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy;1513 typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap;1514 typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector;1515 typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>1516 StmtUsesPair;1517 1518 ASTContext &Ctx = S.getASTContext();1519 1520 const WeakObjectUseMap &WeakMap = CurFn->getWeakObjectUses();1521 1522 // Extract all weak objects that are referenced more than once.1523 SmallVector<StmtUsesPair, 8> UsesByStmt;1524 for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end();1525 I != E; ++I) {1526 const WeakUseVector &Uses = I->second;1527 1528 // Find the first read of the weak object.1529 WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();1530 for ( ; UI != UE; ++UI) {1531 if (UI->isUnsafe())1532 break;1533 }1534 1535 // If there were only writes to this object, don't warn.1536 if (UI == UE)1537 continue;1538 1539 // If there was only one read, followed by any number of writes, and the1540 // read is not within a loop, don't warn. Additionally, don't warn in a1541 // loop if the base object is a local variable -- local variables are often1542 // changed in loops.1543 if (UI == Uses.begin()) {1544 WeakUseVector::const_iterator UI2 = UI;1545 for (++UI2; UI2 != UE; ++UI2)1546 if (UI2->isUnsafe())1547 break;1548 1549 if (UI2 == UE) {1550 if (!isInLoop(Ctx, PM, UI->getUseExpr()))1551 continue;1552 1553 const WeakObjectProfileTy &Profile = I->first;1554 if (!Profile.isExactProfile())1555 continue;1556 1557 const NamedDecl *Base = Profile.getBase();1558 if (!Base)1559 Base = Profile.getProperty();1560 assert(Base && "A profile always has a base or property.");1561 1562 if (const VarDecl *BaseVar = dyn_cast<VarDecl>(Base))1563 if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(Base))1564 continue;1565 }1566 }1567 1568 UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));1569 }1570 1571 if (UsesByStmt.empty())1572 return;1573 1574 // Sort by first use so that we emit the warnings in a deterministic order.1575 SourceManager &SM = S.getSourceManager();1576 llvm::sort(UsesByStmt,1577 [&SM](const StmtUsesPair &LHS, const StmtUsesPair &RHS) {1578 return SM.isBeforeInTranslationUnit(LHS.first->getBeginLoc(),1579 RHS.first->getBeginLoc());1580 });1581 1582 // Classify the current code body for better warning text.1583 // This enum should stay in sync with the cases in1584 // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.1585 // FIXME: Should we use a common classification enum and the same set of1586 // possibilities all throughout Sema?1587 enum {1588 Function,1589 Method,1590 Block,1591 Lambda1592 } FunctionKind;1593 1594 if (isa<sema::BlockScopeInfo>(CurFn))1595 FunctionKind = Block;1596 else if (isa<sema::LambdaScopeInfo>(CurFn))1597 FunctionKind = Lambda;1598 else if (isa<ObjCMethodDecl>(D))1599 FunctionKind = Method;1600 else1601 FunctionKind = Function;1602 1603 // Iterate through the sorted problems and emit warnings for each.1604 for (const auto &P : UsesByStmt) {1605 const Stmt *FirstRead = P.first;1606 const WeakObjectProfileTy &Key = P.second->first;1607 const WeakUseVector &Uses = P.second->second;1608 1609 // For complicated expressions like 'a.b.c' and 'x.b.c', WeakObjectProfileTy1610 // may not contain enough information to determine that these are different1611 // properties. We can only be 100% sure of a repeated use in certain cases,1612 // and we adjust the diagnostic kind accordingly so that the less certain1613 // case can be turned off if it is too noisy.1614 unsigned DiagKind;1615 if (Key.isExactProfile())1616 DiagKind = diag::warn_arc_repeated_use_of_weak;1617 else1618 DiagKind = diag::warn_arc_possible_repeated_use_of_weak;1619 1620 // Classify the weak object being accessed for better warning text.1621 // This enum should stay in sync with the cases in1622 // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.1623 enum {1624 Variable,1625 Property,1626 ImplicitProperty,1627 Ivar1628 } ObjectKind;1629 1630 const NamedDecl *KeyProp = Key.getProperty();1631 if (isa<VarDecl>(KeyProp))1632 ObjectKind = Variable;1633 else if (isa<ObjCPropertyDecl>(KeyProp))1634 ObjectKind = Property;1635 else if (isa<ObjCMethodDecl>(KeyProp))1636 ObjectKind = ImplicitProperty;1637 else if (isa<ObjCIvarDecl>(KeyProp))1638 ObjectKind = Ivar;1639 else1640 llvm_unreachable("Unexpected weak object kind!");1641 1642 // Do not warn about IBOutlet weak property receivers being set to null1643 // since they are typically only used from the main thread.1644 if (const ObjCPropertyDecl *Prop = dyn_cast<ObjCPropertyDecl>(KeyProp))1645 if (Prop->hasAttr<IBOutletAttr>())1646 continue;1647 1648 // Show the first time the object was read.1649 S.Diag(FirstRead->getBeginLoc(), DiagKind)1650 << int(ObjectKind) << KeyProp << int(FunctionKind)1651 << FirstRead->getSourceRange();1652 1653 // Print all the other accesses as notes.1654 for (const auto &Use : Uses) {1655 if (Use.getUseExpr() == FirstRead)1656 continue;1657 S.Diag(Use.getUseExpr()->getBeginLoc(),1658 diag::note_arc_weak_also_accessed_here)1659 << Use.getUseExpr()->getSourceRange();1660 }1661 }1662}1663 1664namespace clang {1665namespace {1666typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;1667typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;1668typedef std::list<DelayedDiag> DiagList;1669 1670struct SortDiagBySourceLocation {1671 SourceManager &SM;1672 SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {}1673 1674 bool operator()(const DelayedDiag &left, const DelayedDiag &right) {1675 // Although this call will be slow, this is only called when outputting1676 // multiple warnings.1677 return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);1678 }1679};1680} // anonymous namespace1681} // namespace clang1682 1683namespace {1684class UninitValsDiagReporter : public UninitVariablesHandler {1685 Sema &S;1686 typedef SmallVector<UninitUse, 2> UsesVec;1687 typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;1688 // Prefer using MapVector to DenseMap, so that iteration order will be1689 // the same as insertion order. This is needed to obtain a deterministic1690 // order of diagnostics when calling flushDiagnostics().1691 typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;1692 UsesMap uses;1693 1694public:1695 UninitValsDiagReporter(Sema &S) : S(S) {}1696 ~UninitValsDiagReporter() override { flushDiagnostics(); }1697 1698 MappedType &getUses(const VarDecl *vd) {1699 MappedType &V = uses[vd];1700 if (!V.getPointer())1701 V.setPointer(new UsesVec());1702 return V;1703 }1704 1705 void handleUseOfUninitVariable(const VarDecl *vd,1706 const UninitUse &use) override {1707 getUses(vd).getPointer()->push_back(use);1708 }1709 1710 void handleSelfInit(const VarDecl *vd) override { getUses(vd).setInt(true); }1711 1712 void flushDiagnostics() {1713 for (const auto &P : uses) {1714 const VarDecl *vd = P.first;1715 const MappedType &V = P.second;1716 1717 UsesVec *vec = V.getPointer();1718 bool hasSelfInit = V.getInt();1719 1720 diagnoseUnitializedVar(vd, hasSelfInit, vec);1721 1722 // Release the uses vector.1723 delete vec;1724 }1725 1726 uses.clear();1727 }1728 1729private:1730 static bool hasAlwaysUninitializedUse(const UsesVec* vec) {1731 return llvm::any_of(*vec, [](const UninitUse &U) {1732 return U.getKind() == UninitUse::Always ||1733 U.getKind() == UninitUse::AfterCall ||1734 U.getKind() == UninitUse::AfterDecl;1735 });1736 }1737 1738 // Print the diagnostic for the variable. We try to warn only on the first1739 // point at which a variable is used uninitialized. After the first1740 // diagnostic is printed, further diagnostics for this variable are skipped.1741 void diagnoseUnitializedVar(const VarDecl *vd, bool hasSelfInit,1742 UsesVec *vec) {1743 // Specially handle the case where we have uses of an uninitialized1744 // variable, but the root cause is an idiomatic self-init. We want1745 // to report the diagnostic at the self-init since that is the root cause.1746 if (hasSelfInit && hasAlwaysUninitializedUse(vec)) {1747 if (DiagnoseUninitializedUse(S, vd,1748 UninitUse(vd->getInit()->IgnoreParenCasts(),1749 /*isAlwaysUninit=*/true),1750 /*alwaysReportSelfInit=*/true))1751 return;1752 }1753 1754 // Sort the uses by their SourceLocations. While not strictly1755 // guaranteed to produce them in line/column order, this will provide1756 // a stable ordering.1757 llvm::sort(*vec, [](const UninitUse &a, const UninitUse &b) {1758 // Prefer the direct use of an uninitialized variable over its use via1759 // constant reference or pointer.1760 if (a.isConstRefOrPtrUse() != b.isConstRefOrPtrUse())1761 return b.isConstRefOrPtrUse();1762 // Prefer a more confident report over a less confident one.1763 if (a.getKind() != b.getKind())1764 return a.getKind() > b.getKind();1765 return a.getUser()->getBeginLoc() < b.getUser()->getBeginLoc();1766 });1767 1768 for (const auto &U : *vec) {1769 if (U.isConstRefUse()) {1770 if (DiagnoseUninitializedConstRefUse(S, vd, U))1771 return;1772 } else if (U.isConstPtrUse()) {1773 if (DiagnoseUninitializedConstPtrUse(S, vd, U))1774 return;1775 } else {1776 // If we have self-init, downgrade all uses to 'may be uninitialized'.1777 UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U;1778 if (DiagnoseUninitializedUse(S, vd, Use))1779 return;1780 }1781 }1782 }1783};1784 1785/// Inter-procedural data for the called-once checker.1786class CalledOnceInterProceduralData {1787public:1788 // Add the delayed warning for the given block.1789 void addDelayedWarning(const BlockDecl *Block,1790 PartialDiagnosticAt &&Warning) {1791 DelayedBlockWarnings[Block].emplace_back(std::move(Warning));1792 }1793 // Report all of the warnings we've gathered for the given block.1794 void flushWarnings(const BlockDecl *Block, Sema &S) {1795 for (const PartialDiagnosticAt &Delayed : DelayedBlockWarnings[Block])1796 S.Diag(Delayed.first, Delayed.second);1797 1798 discardWarnings(Block);1799 }1800 // Discard all of the warnings we've gathered for the given block.1801 void discardWarnings(const BlockDecl *Block) {1802 DelayedBlockWarnings.erase(Block);1803 }1804 1805private:1806 using DelayedDiagnostics = SmallVector<PartialDiagnosticAt, 2>;1807 llvm::DenseMap<const BlockDecl *, DelayedDiagnostics> DelayedBlockWarnings;1808};1809 1810class CalledOnceCheckReporter : public CalledOnceCheckHandler {1811public:1812 CalledOnceCheckReporter(Sema &S, CalledOnceInterProceduralData &Data)1813 : S(S), Data(Data) {}1814 void handleDoubleCall(const ParmVarDecl *Parameter, const Expr *Call,1815 const Expr *PrevCall, bool IsCompletionHandler,1816 bool Poised) override {1817 auto DiagToReport = IsCompletionHandler1818 ? diag::warn_completion_handler_called_twice1819 : diag::warn_called_once_gets_called_twice;1820 S.Diag(Call->getBeginLoc(), DiagToReport) << Parameter;1821 S.Diag(PrevCall->getBeginLoc(), diag::note_called_once_gets_called_twice)1822 << Poised;1823 }1824 1825 void handleNeverCalled(const ParmVarDecl *Parameter,1826 bool IsCompletionHandler) override {1827 auto DiagToReport = IsCompletionHandler1828 ? diag::warn_completion_handler_never_called1829 : diag::warn_called_once_never_called;1830 S.Diag(Parameter->getBeginLoc(), DiagToReport)1831 << Parameter << /* Captured */ false;1832 }1833 1834 void handleNeverCalled(const ParmVarDecl *Parameter, const Decl *Function,1835 const Stmt *Where, NeverCalledReason Reason,1836 bool IsCalledDirectly,1837 bool IsCompletionHandler) override {1838 auto DiagToReport = IsCompletionHandler1839 ? diag::warn_completion_handler_never_called_when1840 : diag::warn_called_once_never_called_when;1841 PartialDiagnosticAt Warning(Where->getBeginLoc(), S.PDiag(DiagToReport)1842 << Parameter1843 << IsCalledDirectly1844 << (unsigned)Reason);1845 1846 if (const auto *Block = dyn_cast<BlockDecl>(Function)) {1847 // We shouldn't report these warnings on blocks immediately1848 Data.addDelayedWarning(Block, std::move(Warning));1849 } else {1850 S.Diag(Warning.first, Warning.second);1851 }1852 }1853 1854 void handleCapturedNeverCalled(const ParmVarDecl *Parameter,1855 const Decl *Where,1856 bool IsCompletionHandler) override {1857 auto DiagToReport = IsCompletionHandler1858 ? diag::warn_completion_handler_never_called1859 : diag::warn_called_once_never_called;1860 S.Diag(Where->getBeginLoc(), DiagToReport)1861 << Parameter << /* Captured */ true;1862 }1863 1864 void1865 handleBlockThatIsGuaranteedToBeCalledOnce(const BlockDecl *Block) override {1866 Data.flushWarnings(Block, S);1867 }1868 1869 void handleBlockWithNoGuarantees(const BlockDecl *Block) override {1870 Data.discardWarnings(Block);1871 }1872 1873private:1874 Sema &S;1875 CalledOnceInterProceduralData &Data;1876};1877 1878constexpr unsigned CalledOnceWarnings[] = {1879 diag::warn_called_once_never_called,1880 diag::warn_called_once_never_called_when,1881 diag::warn_called_once_gets_called_twice};1882 1883constexpr unsigned CompletionHandlerWarnings[]{1884 diag::warn_completion_handler_never_called,1885 diag::warn_completion_handler_never_called_when,1886 diag::warn_completion_handler_called_twice};1887 1888bool shouldAnalyzeCalledOnceImpl(llvm::ArrayRef<unsigned> DiagIDs,1889 const DiagnosticsEngine &Diags,1890 SourceLocation At) {1891 return llvm::any_of(DiagIDs, [&Diags, At](unsigned DiagID) {1892 return !Diags.isIgnored(DiagID, At);1893 });1894}1895 1896bool shouldAnalyzeCalledOnceConventions(const DiagnosticsEngine &Diags,1897 SourceLocation At) {1898 return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);1899}1900 1901bool shouldAnalyzeCalledOnceParameters(const DiagnosticsEngine &Diags,1902 SourceLocation At) {1903 return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||1904 shouldAnalyzeCalledOnceConventions(Diags, At);1905}1906} // anonymous namespace1907 1908//===----------------------------------------------------------------------===//1909// -Wthread-safety1910//===----------------------------------------------------------------------===//1911namespace clang {1912namespace threadSafety {1913namespace {1914class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {1915 Sema &S;1916 DiagList Warnings;1917 SourceLocation FunLocation, FunEndLocation;1918 1919 const FunctionDecl *CurrentFunction;1920 bool Verbose;1921 1922 OptionalNotes getNotes() const {1923 if (Verbose && CurrentFunction) {1924 PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(),1925 S.PDiag(diag::note_thread_warning_in_fun)1926 << CurrentFunction);1927 return OptionalNotes(1, FNote);1928 }1929 return OptionalNotes();1930 }1931 1932 OptionalNotes getNotes(const PartialDiagnosticAt &Note) const {1933 OptionalNotes ONS(1, Note);1934 if (Verbose && CurrentFunction) {1935 PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(),1936 S.PDiag(diag::note_thread_warning_in_fun)1937 << CurrentFunction);1938 ONS.push_back(std::move(FNote));1939 }1940 return ONS;1941 }1942 1943 OptionalNotes getNotes(const PartialDiagnosticAt &Note1,1944 const PartialDiagnosticAt &Note2) const {1945 OptionalNotes ONS;1946 ONS.push_back(Note1);1947 ONS.push_back(Note2);1948 if (Verbose && CurrentFunction) {1949 PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(),1950 S.PDiag(diag::note_thread_warning_in_fun)1951 << CurrentFunction);1952 ONS.push_back(std::move(FNote));1953 }1954 return ONS;1955 }1956 1957 OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) {1958 return LocLocked.isValid()1959 ? getNotes(PartialDiagnosticAt(1960 LocLocked, S.PDiag(diag::note_locked_here) << Kind))1961 : getNotes();1962 }1963 1964 OptionalNotes makeUnlockedHereNote(SourceLocation LocUnlocked,1965 StringRef Kind) {1966 return LocUnlocked.isValid()1967 ? getNotes(PartialDiagnosticAt(1968 LocUnlocked, S.PDiag(diag::note_unlocked_here) << Kind))1969 : getNotes();1970 }1971 1972 OptionalNotes makeManagedMismatchNoteForParam(SourceLocation DeclLoc) {1973 return DeclLoc.isValid()1974 ? getNotes(PartialDiagnosticAt(1975 DeclLoc,1976 S.PDiag(diag::note_managed_mismatch_here_for_param)))1977 : getNotes();1978 }1979 1980 public:1981 ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)1982 : S(S), FunLocation(FL), FunEndLocation(FEL),1983 CurrentFunction(nullptr), Verbose(false) {}1984 1985 void setVerbose(bool b) { Verbose = b; }1986 1987 /// Emit all buffered diagnostics in order of sourcelocation.1988 /// We need to output diagnostics produced while iterating through1989 /// the lockset in deterministic order, so this function orders diagnostics1990 /// and outputs them.1991 void emitDiagnostics() {1992 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));1993 for (const auto &Diag : Warnings) {1994 S.Diag(Diag.first.first, Diag.first.second);1995 for (const auto &Note : Diag.second)1996 S.Diag(Note.first, Note.second);1997 }1998 }1999 2000 void handleUnmatchedUnderlyingMutexes(SourceLocation Loc, SourceLocation DLoc,2001 Name scopeName, StringRef Kind,2002 Name expected, Name actual) override {2003 PartialDiagnosticAt Warning(Loc,2004 S.PDiag(diag::warn_unmatched_underlying_mutexes)2005 << Kind << scopeName << expected << actual);2006 Warnings.emplace_back(std::move(Warning),2007 makeManagedMismatchNoteForParam(DLoc));2008 }2009 2010 void handleExpectMoreUnderlyingMutexes(SourceLocation Loc,2011 SourceLocation DLoc, Name scopeName,2012 StringRef Kind,2013 Name expected) override {2014 PartialDiagnosticAt Warning(2015 Loc, S.PDiag(diag::warn_expect_more_underlying_mutexes)2016 << Kind << scopeName << expected);2017 Warnings.emplace_back(std::move(Warning),2018 makeManagedMismatchNoteForParam(DLoc));2019 }2020 2021 void handleExpectFewerUnderlyingMutexes(SourceLocation Loc,2022 SourceLocation DLoc, Name scopeName,2023 StringRef Kind,2024 Name actual) override {2025 PartialDiagnosticAt Warning(2026 Loc, S.PDiag(diag::warn_expect_fewer_underlying_mutexes)2027 << Kind << scopeName << actual);2028 Warnings.emplace_back(std::move(Warning),2029 makeManagedMismatchNoteForParam(DLoc));2030 }2031 2032 void handleInvalidLockExp(SourceLocation Loc) override {2033 PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_cannot_resolve_lock)2034 << Loc);2035 Warnings.emplace_back(std::move(Warning), getNotes());2036 }2037 2038 void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc,2039 SourceLocation LocPreviousUnlock) override {2040 if (Loc.isInvalid())2041 Loc = FunLocation;2042 PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_but_no_lock)2043 << Kind << LockName);2044 Warnings.emplace_back(std::move(Warning),2045 makeUnlockedHereNote(LocPreviousUnlock, Kind));2046 }2047 2048 void handleIncorrectUnlockKind(StringRef Kind, Name LockName,2049 LockKind Expected, LockKind Received,2050 SourceLocation LocLocked,2051 SourceLocation LocUnlock) override {2052 if (LocUnlock.isInvalid())2053 LocUnlock = FunLocation;2054 PartialDiagnosticAt Warning(2055 LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch)2056 << Kind << LockName << Received << Expected);2057 Warnings.emplace_back(std::move(Warning),2058 makeLockedHereNote(LocLocked, Kind));2059 }2060 2061 void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked,2062 SourceLocation LocDoubleLock) override {2063 if (LocDoubleLock.isInvalid())2064 LocDoubleLock = FunLocation;2065 PartialDiagnosticAt Warning(LocDoubleLock, S.PDiag(diag::warn_double_lock)2066 << Kind << LockName);2067 Warnings.emplace_back(std::move(Warning),2068 makeLockedHereNote(LocLocked, Kind));2069 }2070 2071 void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,2072 SourceLocation LocLocked,2073 SourceLocation LocEndOfScope,2074 LockErrorKind LEK,2075 bool ReentrancyMismatch) override {2076 unsigned DiagID = 0;2077 switch (LEK) {2078 case LEK_LockedSomePredecessors:2079 DiagID = diag::warn_lock_some_predecessors;2080 break;2081 case LEK_LockedSomeLoopIterations:2082 DiagID = diag::warn_expecting_lock_held_on_loop;2083 break;2084 case LEK_LockedAtEndOfFunction:2085 DiagID = diag::warn_no_unlock;2086 break;2087 case LEK_NotLockedAtEndOfFunction:2088 DiagID = diag::warn_expecting_locked;2089 break;2090 }2091 if (LocEndOfScope.isInvalid())2092 LocEndOfScope = FunEndLocation;2093 2094 PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID)2095 << Kind << LockName2096 << ReentrancyMismatch);2097 Warnings.emplace_back(std::move(Warning),2098 makeLockedHereNote(LocLocked, Kind));2099 }2100 2101 void handleExclusiveAndShared(StringRef Kind, Name LockName,2102 SourceLocation Loc1,2103 SourceLocation Loc2) override {2104 PartialDiagnosticAt Warning(Loc1,2105 S.PDiag(diag::warn_lock_exclusive_and_shared)2106 << Kind << LockName);2107 PartialDiagnosticAt Note(Loc2, S.PDiag(diag::note_lock_exclusive_and_shared)2108 << Kind << LockName);2109 Warnings.emplace_back(std::move(Warning), getNotes(Note));2110 }2111 2112 void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK,2113 AccessKind AK, SourceLocation Loc) override {2114 unsigned DiagID = 0;2115 switch (POK) {2116 case POK_VarAccess:2117 case POK_PassByRef:2118 case POK_ReturnByRef:2119 case POK_PassPointer:2120 case POK_ReturnPointer:2121 DiagID = diag::warn_variable_requires_any_lock;2122 break;2123 case POK_VarDereference:2124 case POK_PtPassByRef:2125 case POK_PtReturnByRef:2126 case POK_PtPassPointer:2127 case POK_PtReturnPointer:2128 DiagID = diag::warn_var_deref_requires_any_lock;2129 break;2130 case POK_FunctionCall:2131 llvm_unreachable("Only works for variables");2132 break;2133 }2134 PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)2135 << D << getLockKindFromAccessKind(AK));2136 Warnings.emplace_back(std::move(Warning), getNotes());2137 }2138 2139 void handleMutexNotHeld(StringRef Kind, const NamedDecl *D,2140 ProtectedOperationKind POK, Name LockName,2141 LockKind LK, SourceLocation Loc,2142 Name *PossibleMatch) override {2143 unsigned DiagID = 0;2144 if (PossibleMatch) {2145 switch (POK) {2146 case POK_VarAccess:2147 DiagID = diag::warn_variable_requires_lock_precise;2148 break;2149 case POK_VarDereference:2150 DiagID = diag::warn_var_deref_requires_lock_precise;2151 break;2152 case POK_FunctionCall:2153 DiagID = diag::warn_fun_requires_lock_precise;2154 break;2155 case POK_PassByRef:2156 DiagID = diag::warn_guarded_pass_by_reference;2157 break;2158 case POK_PtPassByRef:2159 DiagID = diag::warn_pt_guarded_pass_by_reference;2160 break;2161 case POK_ReturnByRef:2162 DiagID = diag::warn_guarded_return_by_reference;2163 break;2164 case POK_PtReturnByRef:2165 DiagID = diag::warn_pt_guarded_return_by_reference;2166 break;2167 case POK_PassPointer:2168 DiagID = diag::warn_guarded_pass_pointer;2169 break;2170 case POK_PtPassPointer:2171 DiagID = diag::warn_pt_guarded_pass_pointer;2172 break;2173 case POK_ReturnPointer:2174 DiagID = diag::warn_guarded_return_pointer;2175 break;2176 case POK_PtReturnPointer:2177 DiagID = diag::warn_pt_guarded_return_pointer;2178 break;2179 }2180 PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind2181 << D2182 << LockName << LK);2183 PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match)2184 << *PossibleMatch);2185 if (Verbose && POK == POK_VarAccess) {2186 PartialDiagnosticAt VNote(D->getLocation(),2187 S.PDiag(diag::note_guarded_by_declared_here)2188 << D->getDeclName());2189 Warnings.emplace_back(std::move(Warning), getNotes(Note, VNote));2190 } else2191 Warnings.emplace_back(std::move(Warning), getNotes(Note));2192 } else {2193 switch (POK) {2194 case POK_VarAccess:2195 DiagID = diag::warn_variable_requires_lock;2196 break;2197 case POK_VarDereference:2198 DiagID = diag::warn_var_deref_requires_lock;2199 break;2200 case POK_FunctionCall:2201 DiagID = diag::warn_fun_requires_lock;2202 break;2203 case POK_PassByRef:2204 DiagID = diag::warn_guarded_pass_by_reference;2205 break;2206 case POK_PtPassByRef:2207 DiagID = diag::warn_pt_guarded_pass_by_reference;2208 break;2209 case POK_ReturnByRef:2210 DiagID = diag::warn_guarded_return_by_reference;2211 break;2212 case POK_PtReturnByRef:2213 DiagID = diag::warn_pt_guarded_return_by_reference;2214 break;2215 case POK_PassPointer:2216 DiagID = diag::warn_guarded_pass_pointer;2217 break;2218 case POK_PtPassPointer:2219 DiagID = diag::warn_pt_guarded_pass_pointer;2220 break;2221 case POK_ReturnPointer:2222 DiagID = diag::warn_guarded_return_pointer;2223 break;2224 case POK_PtReturnPointer:2225 DiagID = diag::warn_pt_guarded_return_pointer;2226 break;2227 }2228 PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind2229 << D2230 << LockName << LK);2231 if (Verbose && POK == POK_VarAccess) {2232 PartialDiagnosticAt Note(D->getLocation(),2233 S.PDiag(diag::note_guarded_by_declared_here));2234 Warnings.emplace_back(std::move(Warning), getNotes(Note));2235 } else2236 Warnings.emplace_back(std::move(Warning), getNotes());2237 }2238 }2239 2240 void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,2241 SourceLocation Loc) override {2242 PartialDiagnosticAt Warning(Loc,2243 S.PDiag(diag::warn_acquire_requires_negative_cap)2244 << Kind << LockName << Neg);2245 Warnings.emplace_back(std::move(Warning), getNotes());2246 }2247 2248 void handleNegativeNotHeld(const NamedDecl *D, Name LockName,2249 SourceLocation Loc) override {2250 PartialDiagnosticAt Warning(2251 Loc, S.PDiag(diag::warn_fun_requires_negative_cap) << D << LockName);2252 Warnings.emplace_back(std::move(Warning), getNotes());2253 }2254 2255 void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,2256 SourceLocation Loc) override {2257 PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_fun_excludes_mutex)2258 << Kind << FunName << LockName);2259 Warnings.emplace_back(std::move(Warning), getNotes());2260 }2261 2262 void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,2263 SourceLocation Loc) override {2264 PartialDiagnosticAt Warning(Loc,2265 S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);2266 Warnings.emplace_back(std::move(Warning), getNotes());2267 }2268 2269 void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) override {2270 PartialDiagnosticAt Warning(Loc,2271 S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);2272 Warnings.emplace_back(std::move(Warning), getNotes());2273 }2274 2275 void enterFunction(const FunctionDecl* FD) override {2276 CurrentFunction = FD;2277 }2278 2279 void leaveFunction(const FunctionDecl* FD) override {2280 CurrentFunction = nullptr;2281 }2282};2283} // anonymous namespace2284} // namespace threadSafety2285} // namespace clang2286 2287//===----------------------------------------------------------------------===//2288// -Wconsumed2289//===----------------------------------------------------------------------===//2290 2291namespace clang {2292namespace consumed {2293namespace {2294class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {2295 2296 Sema &S;2297 DiagList Warnings;2298 2299public:2300 2301 ConsumedWarningsHandler(Sema &S) : S(S) {}2302 2303 void emitDiagnostics() override {2304 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));2305 for (const auto &Diag : Warnings) {2306 S.Diag(Diag.first.first, Diag.first.second);2307 for (const auto &Note : Diag.second)2308 S.Diag(Note.first, Note.second);2309 }2310 }2311 2312 void warnLoopStateMismatch(SourceLocation Loc,2313 StringRef VariableName) override {2314 PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch) <<2315 VariableName);2316 2317 Warnings.emplace_back(std::move(Warning), OptionalNotes());2318 }2319 2320 void warnParamReturnTypestateMismatch(SourceLocation Loc,2321 StringRef VariableName,2322 StringRef ExpectedState,2323 StringRef ObservedState) override {2324 2325 PartialDiagnosticAt Warning(Loc, S.PDiag(2326 diag::warn_param_return_typestate_mismatch) << VariableName <<2327 ExpectedState << ObservedState);2328 2329 Warnings.emplace_back(std::move(Warning), OptionalNotes());2330 }2331 2332 void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,2333 StringRef ObservedState) override {2334 2335 PartialDiagnosticAt Warning(Loc, S.PDiag(2336 diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);2337 2338 Warnings.emplace_back(std::move(Warning), OptionalNotes());2339 }2340 2341 void warnReturnTypestateForUnconsumableType(SourceLocation Loc,2342 StringRef TypeName) override {2343 PartialDiagnosticAt Warning(Loc, S.PDiag(2344 diag::warn_return_typestate_for_unconsumable_type) << TypeName);2345 2346 Warnings.emplace_back(std::move(Warning), OptionalNotes());2347 }2348 2349 void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,2350 StringRef ObservedState) override {2351 2352 PartialDiagnosticAt Warning(Loc, S.PDiag(2353 diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);2354 2355 Warnings.emplace_back(std::move(Warning), OptionalNotes());2356 }2357 2358 void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,2359 SourceLocation Loc) override {2360 2361 PartialDiagnosticAt Warning(Loc, S.PDiag(2362 diag::warn_use_of_temp_in_invalid_state) << MethodName << State);2363 2364 Warnings.emplace_back(std::move(Warning), OptionalNotes());2365 }2366 2367 void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,2368 StringRef State, SourceLocation Loc) override {2369 2370 PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) <<2371 MethodName << VariableName << State);2372 2373 Warnings.emplace_back(std::move(Warning), OptionalNotes());2374 }2375};2376} // anonymous namespace2377} // namespace consumed2378} // namespace clang2379 2380//===----------------------------------------------------------------------===//2381// Unsafe buffer usage analysis.2382//===----------------------------------------------------------------------===//2383 2384namespace {2385class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {2386 Sema &S;2387 bool SuggestSuggestions; // Recommend -fsafe-buffer-usage-suggestions?2388 2389 // Lists as a string the names of variables in `VarGroupForVD` except for `VD`2390 // itself:2391 std::string listVariableGroupAsString(2392 const VarDecl *VD, const ArrayRef<const VarDecl *> &VarGroupForVD) const {2393 if (VarGroupForVD.size() <= 1)2394 return "";2395 2396 std::vector<StringRef> VarNames;2397 auto PutInQuotes = [](StringRef S) -> std::string {2398 return "'" + S.str() + "'";2399 };2400 2401 for (auto *V : VarGroupForVD) {2402 if (V == VD)2403 continue;2404 VarNames.push_back(V->getName());2405 }2406 if (VarNames.size() == 1) {2407 return PutInQuotes(VarNames[0]);2408 }2409 if (VarNames.size() == 2) {2410 return PutInQuotes(VarNames[0]) + " and " + PutInQuotes(VarNames[1]);2411 }2412 assert(VarGroupForVD.size() > 3);2413 const unsigned N = VarNames.size() -2414 2; // need to print the last two names as "..., X, and Y"2415 std::string AllVars = "";2416 2417 for (unsigned I = 0; I < N; ++I)2418 AllVars.append(PutInQuotes(VarNames[I]) + ", ");2419 AllVars.append(PutInQuotes(VarNames[N]) + ", and " +2420 PutInQuotes(VarNames[N + 1]));2421 return AllVars;2422 }2423 2424public:2425 UnsafeBufferUsageReporter(Sema &S, bool SuggestSuggestions)2426 : S(S), SuggestSuggestions(SuggestSuggestions) {}2427 2428 void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl,2429 ASTContext &Ctx) override {2430 SourceLocation Loc;2431 SourceRange Range;2432 unsigned MsgParam = 0;2433 NamedDecl *D = nullptr;2434 if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {2435 Loc = ASE->getBase()->getExprLoc();2436 Range = ASE->getBase()->getSourceRange();2437 MsgParam = 2;2438 } else if (const auto *BO = dyn_cast<BinaryOperator>(Operation)) {2439 BinaryOperator::Opcode Op = BO->getOpcode();2440 if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||2441 Op == BO_SubAssign) {2442 if (BO->getRHS()->getType()->isIntegerType()) {2443 Loc = BO->getLHS()->getExprLoc();2444 Range = BO->getLHS()->getSourceRange();2445 } else {2446 Loc = BO->getRHS()->getExprLoc();2447 Range = BO->getRHS()->getSourceRange();2448 }2449 MsgParam = 1;2450 }2451 } else if (const auto *UO = dyn_cast<UnaryOperator>(Operation)) {2452 UnaryOperator::Opcode Op = UO->getOpcode();2453 if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||2454 Op == UO_PostDec) {2455 Loc = UO->getSubExpr()->getExprLoc();2456 Range = UO->getSubExpr()->getSourceRange();2457 MsgParam = 1;2458 }2459 } else {2460 if (isa<CallExpr>(Operation) || isa<CXXConstructExpr>(Operation)) {2461 // note_unsafe_buffer_operation doesn't have this mode yet.2462 assert(!IsRelatedToDecl && "Not implemented yet!");2463 MsgParam = 3;2464 } else if (isa<MemberExpr>(Operation)) {2465 // note_unsafe_buffer_operation doesn't have this mode yet.2466 assert(!IsRelatedToDecl && "Not implemented yet!");2467 auto *ME = cast<MemberExpr>(Operation);2468 D = ME->getMemberDecl();2469 MsgParam = 5;2470 } else if (const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) {2471 QualType destType = ECE->getType();2472 bool destTypeComplete = true;2473 2474 if (!isa<PointerType>(destType))2475 return;2476 destType = destType.getTypePtr()->getPointeeType();2477 if (const auto *D = destType->getAsTagDecl())2478 destTypeComplete = D->isCompleteDefinition();2479 2480 // If destination type is incomplete, it is unsafe to cast to anyway, no2481 // need to check its type:2482 if (destTypeComplete) {2483 const uint64_t dSize = Ctx.getTypeSize(destType);2484 QualType srcType = ECE->getSubExpr()->getType();2485 2486 assert(srcType->isPointerType());2487 2488 const uint64_t sSize =2489 Ctx.getTypeSize(srcType.getTypePtr()->getPointeeType());2490 2491 if (sSize >= dSize)2492 return;2493 }2494 if (const auto *CE = dyn_cast<CXXMemberCallExpr>(2495 ECE->getSubExpr()->IgnoreParens())) {2496 D = CE->getMethodDecl();2497 }2498 2499 if (!D)2500 return;2501 2502 MsgParam = 4;2503 }2504 Loc = Operation->getBeginLoc();2505 Range = Operation->getSourceRange();2506 }2507 if (IsRelatedToDecl) {2508 assert(!SuggestSuggestions &&2509 "Variables blamed for unsafe buffer usage without suggestions!");2510 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;2511 } else {2512 if (D) {2513 S.Diag(Loc, diag::warn_unsafe_buffer_operation)2514 << MsgParam << D << Range;2515 } else {2516 S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam << Range;2517 }2518 if (SuggestSuggestions) {2519 S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled);2520 }2521 }2522 }2523 2524 void handleUnsafeLibcCall(const CallExpr *Call, unsigned PrintfInfo,2525 ASTContext &Ctx,2526 const Expr *UnsafeArg = nullptr) override {2527 S.Diag(Call->getBeginLoc(), diag::warn_unsafe_buffer_libc_call)2528 << Call->getDirectCallee() // We've checked there is a direct callee2529 << Call->getSourceRange();2530 if (PrintfInfo > 0) {2531 SourceRange R =2532 UnsafeArg ? UnsafeArg->getSourceRange() : Call->getSourceRange();2533 S.Diag(R.getBegin(), diag::note_unsafe_buffer_printf_call)2534 << PrintfInfo << R;2535 }2536 }2537 2538 void handleUnsafeOperationInContainer(const Stmt *Operation,2539 bool IsRelatedToDecl,2540 ASTContext &Ctx) override {2541 SourceLocation Loc;2542 SourceRange Range;2543 unsigned MsgParam = 0;2544 2545 // This function only handles SpanTwoParamConstructorGadget so far, which2546 // always gives a CXXConstructExpr.2547 const auto *CtorExpr = cast<CXXConstructExpr>(Operation);2548 Loc = CtorExpr->getLocation();2549 2550 S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container);2551 if (IsRelatedToDecl) {2552 assert(!SuggestSuggestions &&2553 "Variables blamed for unsafe buffer usage without suggestions!");2554 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;2555 }2556 }2557 2558 void handleUnsafeVariableGroup(const VarDecl *Variable,2559 const VariableGroupsManager &VarGrpMgr,2560 FixItList &&Fixes, const Decl *D,2561 const FixitStrategy &VarTargetTypes) override {2562 assert(!SuggestSuggestions &&2563 "Unsafe buffer usage fixits displayed without suggestions!");2564 S.Diag(Variable->getLocation(), diag::warn_unsafe_buffer_variable)2565 << Variable << (Variable->getType()->isPointerType() ? 0 : 1)2566 << Variable->getSourceRange();2567 if (!Fixes.empty()) {2568 assert(isa<NamedDecl>(D) &&2569 "Fix-its are generated only for `NamedDecl`s");2570 const NamedDecl *ND = cast<NamedDecl>(D);2571 bool BriefMsg = false;2572 // If the variable group involves parameters, the diagnostic message will2573 // NOT explain how the variables are grouped as the reason is non-trivial2574 // and irrelavant to users' experience:2575 const auto VarGroupForVD = VarGrpMgr.getGroupOfVar(Variable, &BriefMsg);2576 unsigned FixItStrategy = 0;2577 switch (VarTargetTypes.lookup(Variable)) {2578 case clang::FixitStrategy::Kind::Span:2579 FixItStrategy = 0;2580 break;2581 case clang::FixitStrategy::Kind::Array:2582 FixItStrategy = 1;2583 break;2584 default:2585 assert(false && "We support only std::span and std::array");2586 };2587 2588 const auto &FD =2589 S.Diag(Variable->getLocation(),2590 BriefMsg ? diag::note_unsafe_buffer_variable_fixit_together2591 : diag::note_unsafe_buffer_variable_fixit_group);2592 2593 FD << Variable << FixItStrategy;2594 FD << listVariableGroupAsString(Variable, VarGroupForVD)2595 << (VarGroupForVD.size() > 1) << ND;2596 for (const auto &F : Fixes) {2597 FD << F;2598 }2599 }2600 2601#ifndef NDEBUG2602 if (areDebugNotesRequested())2603 for (const DebugNote &Note: DebugNotesByVar[Variable])2604 S.Diag(Note.first, diag::note_safe_buffer_debug_mode) << Note.second;2605#endif2606 }2607 2608 void handleUnsafeUniquePtrArrayAccess(const DynTypedNode &Node,2609 bool IsRelatedToDecl,2610 ASTContext &Ctx) override {2611 SourceLocation Loc;2612 2613 Loc = Node.get<Stmt>()->getBeginLoc();2614 S.Diag(Loc, diag::warn_unsafe_buffer_usage_unique_ptr_array_access)2615 << Node.getSourceRange();2616 }2617 2618 bool isSafeBufferOptOut(const SourceLocation &Loc) const override {2619 return S.PP.isSafeBufferOptOut(S.getSourceManager(), Loc);2620 }2621 2622 bool ignoreUnsafeBufferInContainer(const SourceLocation &Loc) const override {2623 return S.Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container, Loc);2624 }2625 2626 bool ignoreUnsafeBufferInLibcCall(const SourceLocation &Loc) const override {2627 return S.Diags.isIgnored(diag::warn_unsafe_buffer_libc_call, Loc);2628 }2629 2630 // Returns the text representation of clang::unsafe_buffer_usage attribute.2631 // `WSSuffix` holds customized "white-space"s, e.g., newline or whilespace2632 // characters.2633 std::string2634 getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,2635 StringRef WSSuffix = "") const override {2636 Preprocessor &PP = S.getPreprocessor();2637 TokenValue ClangUnsafeBufferUsageTokens[] = {2638 tok::l_square,2639 tok::l_square,2640 PP.getIdentifierInfo("clang"),2641 tok::coloncolon,2642 PP.getIdentifierInfo("unsafe_buffer_usage"),2643 tok::r_square,2644 tok::r_square};2645 2646 StringRef MacroName;2647 2648 // The returned macro (it returns) is guaranteed not to be function-like:2649 MacroName = PP.getLastMacroWithSpelling(Loc, ClangUnsafeBufferUsageTokens);2650 if (MacroName.empty())2651 MacroName = "[[clang::unsafe_buffer_usage]]";2652 return MacroName.str() + WSSuffix.str();2653 }2654};2655} // namespace2656 2657//===----------------------------------------------------------------------===//2658// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based2659// warnings on a function, method, or block.2660//===----------------------------------------------------------------------===//2661 2662sema::AnalysisBasedWarnings::Policy::Policy() {2663 enableCheckFallThrough = 1;2664 enableCheckUnreachable = 0;2665 enableThreadSafetyAnalysis = 0;2666 enableConsumedAnalysis = 0;2667}2668 2669/// InterProceduralData aims to be a storage of whatever data should be passed2670/// between analyses of different functions.2671///2672/// At the moment, its primary goal is to make the information gathered during2673/// the analysis of the blocks available during the analysis of the enclosing2674/// function. This is important due to the fact that blocks are analyzed before2675/// the enclosed function is even parsed fully, so it is not viable to access2676/// anything in the outer scope while analyzing the block. On the other hand,2677/// re-building CFG for blocks and re-analyzing them when we do have all the2678/// information (i.e. during the analysis of the enclosing function) seems to be2679/// ill-designed.2680class sema::AnalysisBasedWarnings::InterProceduralData {2681public:2682 // It is important to analyze blocks within functions because it's a very2683 // common pattern to capture completion handler parameters by blocks.2684 CalledOnceInterProceduralData CalledOnceData;2685};2686 2687template <typename... Ts>2688static bool areAnyEnabled(DiagnosticsEngine &D, SourceLocation Loc,2689 Ts... Diags) {2690 return (!D.isIgnored(Diags, Loc) || ...);2691}2692 2693sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)2694 : S(s), IPData(std::make_unique<InterProceduralData>()),2695 NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),2696 MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),2697 NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),2698 NumUninitAnalysisBlockVisits(0),2699 MaxUninitAnalysisBlockVisitsPerFunction(0) {2700}2701 2702// We need this here for unique_ptr with forward declared class.2703sema::AnalysisBasedWarnings::~AnalysisBasedWarnings() = default;2704 2705sema::AnalysisBasedWarnings::Policy2706sema::AnalysisBasedWarnings::getPolicyInEffectAt(SourceLocation Loc) {2707 using namespace diag;2708 DiagnosticsEngine &D = S.getDiagnostics();2709 Policy P;2710 2711 // Note: The enabled checks should be kept in sync with the switch in2712 // SemaPPCallbacks::PragmaDiagnostic().2713 P.enableCheckUnreachable =2714 PolicyOverrides.enableCheckUnreachable ||2715 areAnyEnabled(D, Loc, warn_unreachable, warn_unreachable_break,2716 warn_unreachable_return, warn_unreachable_loop_increment);2717 2718 P.enableThreadSafetyAnalysis = PolicyOverrides.enableThreadSafetyAnalysis ||2719 areAnyEnabled(D, Loc, warn_double_lock);2720 2721 P.enableConsumedAnalysis = PolicyOverrides.enableConsumedAnalysis ||2722 areAnyEnabled(D, Loc, warn_use_in_invalid_state);2723 return P;2724}2725 2726void sema::AnalysisBasedWarnings::clearOverrides() {2727 PolicyOverrides.enableCheckUnreachable = false;2728 PolicyOverrides.enableConsumedAnalysis = false;2729 PolicyOverrides.enableThreadSafetyAnalysis = false;2730}2731 2732static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope) {2733 for (const auto &D : fscope->PossiblyUnreachableDiags)2734 S.Diag(D.Loc, D.PD);2735}2736 2737template <typename Iterator>2738static void emitPossiblyUnreachableDiags(Sema &S, AnalysisDeclContext &AC,2739 std::pair<Iterator, Iterator> PUDs) {2740 2741 if (PUDs.first == PUDs.second)2742 return;2743 2744 for (auto I = PUDs.first; I != PUDs.second; ++I) {2745 for (const Stmt *S : I->Stmts)2746 AC.registerForcedBlockExpression(S);2747 }2748 2749 if (AC.getCFG()) {2750 CFGReverseBlockReachabilityAnalysis *Analysis =2751 AC.getCFGReachablityAnalysis();2752 2753 for (auto I = PUDs.first; I != PUDs.second; ++I) {2754 const auto &D = *I;2755 if (llvm::all_of(D.Stmts, [&](const Stmt *St) {2756 const CFGBlock *Block = AC.getBlockForRegisteredExpression(St);2757 // FIXME: We should be able to assert that block is non-null, but2758 // the CFG analysis can skip potentially-evaluated expressions in2759 // edge cases; see test/Sema/vla-2.c.2760 if (Block && Analysis)2761 if (!Analysis->isReachable(&AC.getCFG()->getEntry(), Block))2762 return false;2763 return true;2764 })) {2765 S.Diag(D.Loc, D.PD);2766 }2767 }2768 } else {2769 for (auto I = PUDs.first; I != PUDs.second; ++I)2770 S.Diag(I->Loc, I->PD);2771 }2772}2773 2774void sema::AnalysisBasedWarnings::registerVarDeclWarning(2775 VarDecl *VD, clang::sema::PossiblyUnreachableDiag PUD) {2776 VarDeclPossiblyUnreachableDiags.emplace(VD, PUD);2777}2778 2779void sema::AnalysisBasedWarnings::issueWarningsForRegisteredVarDecl(2780 VarDecl *VD) {2781 if (!llvm::is_contained(VarDeclPossiblyUnreachableDiags, VD))2782 return;2783 2784 AnalysisDeclContext AC(/*Mgr=*/nullptr, VD);2785 2786 AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true;2787 AC.getCFGBuildOptions().AddEHEdges = false;2788 AC.getCFGBuildOptions().AddInitializers = true;2789 AC.getCFGBuildOptions().AddImplicitDtors = true;2790 AC.getCFGBuildOptions().AddTemporaryDtors = true;2791 AC.getCFGBuildOptions().AddCXXNewAllocator = false;2792 AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true;2793 2794 auto Range = VarDeclPossiblyUnreachableDiags.equal_range(VD);2795 auto SecondRange =2796 llvm::make_second_range(llvm::make_range(Range.first, Range.second));2797 emitPossiblyUnreachableDiags(2798 S, AC, std::make_pair(SecondRange.begin(), SecondRange.end()));2799}2800 2801// An AST Visitor that calls a callback function on each callable DEFINITION2802// that is NOT in a dependent context:2803class CallableVisitor : public DynamicRecursiveASTVisitor {2804private:2805 llvm::function_ref<void(const Decl *)> Callback;2806 const Module *const TUModule;2807 2808public:2809 CallableVisitor(llvm::function_ref<void(const Decl *)> Callback,2810 const Module *const TUModule)2811 : Callback(Callback), TUModule(TUModule) {2812 ShouldVisitTemplateInstantiations = true;2813 ShouldVisitImplicitCode = false;2814 }2815 2816 bool TraverseDecl(Decl *Node) override {2817 // For performance reasons, only validate the current translation unit's2818 // module, and not modules it depends on.2819 // See https://issues.chromium.org/issues/351909443 for details.2820 if (Node && Node->getOwningModule() == TUModule)2821 return DynamicRecursiveASTVisitor::TraverseDecl(Node);2822 return true;2823 }2824 2825 bool VisitFunctionDecl(FunctionDecl *Node) override {2826 if (cast<DeclContext>(Node)->isDependentContext())2827 return true; // Not to analyze dependent decl2828 // `FunctionDecl->hasBody()` returns true if the function has a body2829 // somewhere defined. But we want to know if this `Node` has a body2830 // child. So we use `doesThisDeclarationHaveABody`:2831 if (Node->doesThisDeclarationHaveABody())2832 Callback(Node);2833 return true;2834 }2835 2836 bool VisitBlockDecl(BlockDecl *Node) override {2837 if (cast<DeclContext>(Node)->isDependentContext())2838 return true; // Not to analyze dependent decl2839 Callback(Node);2840 return true;2841 }2842 2843 bool VisitObjCMethodDecl(ObjCMethodDecl *Node) override {2844 if (cast<DeclContext>(Node)->isDependentContext())2845 return true; // Not to analyze dependent decl2846 if (Node->hasBody())2847 Callback(Node);2848 return true;2849 }2850 2851 bool VisitLambdaExpr(LambdaExpr *Node) override {2852 return VisitFunctionDecl(Node->getCallOperator());2853 }2854};2855 2856namespace clang::lifetimes {2857namespace {2858class LifetimeSafetyReporterImpl : public LifetimeSafetyReporter {2859 2860public:2861 LifetimeSafetyReporterImpl(Sema &S) : S(S) {}2862 2863 void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,2864 SourceLocation FreeLoc, Confidence C) override {2865 S.Diag(IssueExpr->getExprLoc(),2866 C == Confidence::Definite2867 ? diag::warn_lifetime_safety_loan_expires_permissive2868 : diag::warn_lifetime_safety_loan_expires_strict)2869 << IssueExpr->getEndLoc();2870 S.Diag(FreeLoc, diag::note_lifetime_safety_destroyed_here);2871 S.Diag(UseExpr->getExprLoc(), diag::note_lifetime_safety_used_here)2872 << UseExpr->getEndLoc();2873 }2874 2875 void reportUseAfterReturn(const Expr *IssueExpr, const Expr *EscapeExpr,2876 SourceLocation ExpiryLoc, Confidence C) override {2877 S.Diag(IssueExpr->getExprLoc(),2878 C == Confidence::Definite2879 ? diag::warn_lifetime_safety_return_stack_addr_permissive2880 : diag::warn_lifetime_safety_return_stack_addr_strict)2881 << IssueExpr->getEndLoc();2882 2883 S.Diag(EscapeExpr->getExprLoc(), diag::note_lifetime_safety_returned_here)2884 << EscapeExpr->getEndLoc();2885 }2886 2887private:2888 Sema &S;2889};2890} // namespace2891} // namespace clang::lifetimes2892 2893void clang::sema::AnalysisBasedWarnings::IssueWarnings(2894 TranslationUnitDecl *TU) {2895 if (!TU)2896 return; // This is unexpected, give up quietly.2897 2898 DiagnosticsEngine &Diags = S.getDiagnostics();2899 2900 if (S.hasUncompilableErrorOccurred() || Diags.getIgnoreAllWarnings())2901 // exit if having uncompilable errors or ignoring all warnings:2902 return;2903 2904 DiagnosticOptions &DiagOpts = Diags.getDiagnosticOptions();2905 2906 // UnsafeBufferUsage analysis settings.2907 bool UnsafeBufferUsageCanEmitSuggestions = S.getLangOpts().CPlusPlus20;2908 bool UnsafeBufferUsageShouldEmitSuggestions = // Should != Can.2909 UnsafeBufferUsageCanEmitSuggestions &&2910 DiagOpts.ShowSafeBufferUsageSuggestions;2911 bool UnsafeBufferUsageShouldSuggestSuggestions =2912 UnsafeBufferUsageCanEmitSuggestions &&2913 !DiagOpts.ShowSafeBufferUsageSuggestions;2914 UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions);2915 2916 // The Callback function that performs analyses:2917 auto CallAnalyzers = [&](const Decl *Node) -> void {2918 if (Node->hasAttr<UnsafeBufferUsageAttr>())2919 return;2920 2921 // Perform unsafe buffer usage analysis:2922 if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation,2923 Node->getBeginLoc()) ||2924 !Diags.isIgnored(diag::warn_unsafe_buffer_variable,2925 Node->getBeginLoc()) ||2926 !Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container,2927 Node->getBeginLoc()) ||2928 !Diags.isIgnored(diag::warn_unsafe_buffer_libc_call,2929 Node->getBeginLoc())) {2930 clang::checkUnsafeBufferUsage(Node, R,2931 UnsafeBufferUsageShouldEmitSuggestions);2932 }2933 2934 // More analysis ...2935 };2936 // Emit per-function analysis-based warnings that require the whole-TU2937 // reasoning. Check if any of them is enabled at all before scanning the AST:2938 if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, SourceLocation()) ||2939 !Diags.isIgnored(diag::warn_unsafe_buffer_variable, SourceLocation()) ||2940 !Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container,2941 SourceLocation()) ||2942 (!Diags.isIgnored(diag::warn_unsafe_buffer_libc_call, SourceLocation()) &&2943 S.getLangOpts().CPlusPlus /* only warn about libc calls in C++ */)) {2944 CallableVisitor(CallAnalyzers, TU->getOwningModule())2945 .TraverseTranslationUnitDecl(TU);2946 }2947}2948 2949void clang::sema::AnalysisBasedWarnings::IssueWarnings(2950 sema::AnalysisBasedWarnings::Policy P, sema::FunctionScopeInfo *fscope,2951 const Decl *D, QualType BlockType) {2952 2953 // We avoid doing analysis-based warnings when there are errors for2954 // two reasons:2955 // (1) The CFGs often can't be constructed (if the body is invalid), so2956 // don't bother trying.2957 // (2) The code already has problems; running the analysis just takes more2958 // time.2959 DiagnosticsEngine &Diags = S.getDiagnostics();2960 2961 // Do not do any analysis if we are going to just ignore them.2962 if (Diags.getIgnoreAllWarnings() ||2963 (Diags.getSuppressSystemWarnings() &&2964 S.SourceMgr.isInSystemHeader(D->getLocation())))2965 return;2966 2967 // For code in dependent contexts, we'll do this at instantiation time.2968 if (cast<DeclContext>(D)->isDependentContext())2969 return;2970 2971 if (S.hasUncompilableErrorOccurred()) {2972 // Flush out any possibly unreachable diagnostics.2973 flushDiagnostics(S, fscope);2974 return;2975 }2976 2977 const Stmt *Body = D->getBody();2978 assert(Body);2979 2980 // Construct the analysis context with the specified CFG build options.2981 AnalysisDeclContext AC(/* AnalysisDeclContextManager */ nullptr, D);2982 2983 // Don't generate EH edges for CallExprs as we'd like to avoid the n^22984 // explosion for destructors that can result and the compile time hit.2985 AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true;2986 AC.getCFGBuildOptions().AddEHEdges = false;2987 AC.getCFGBuildOptions().AddInitializers = true;2988 AC.getCFGBuildOptions().AddImplicitDtors = true;2989 AC.getCFGBuildOptions().AddTemporaryDtors = true;2990 AC.getCFGBuildOptions().AddCXXNewAllocator = false;2991 AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true;2992 2993 bool EnableLifetimeSafetyAnalysis = S.getLangOpts().EnableLifetimeSafety;2994 2995 if (EnableLifetimeSafetyAnalysis)2996 AC.getCFGBuildOptions().AddLifetime = true;2997 2998 // Force that certain expressions appear as CFGElements in the CFG. This2999 // is used to speed up various analyses.3000 // FIXME: This isn't the right factoring. This is here for initial3001 // prototyping, but we need a way for analyses to say what expressions they3002 // expect to always be CFGElements and then fill in the BuildOptions3003 // appropriately. This is essentially a layering violation.3004 if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||3005 P.enableConsumedAnalysis || EnableLifetimeSafetyAnalysis) {3006 // Unreachable code analysis and thread safety require a linearized CFG.3007 AC.getCFGBuildOptions().setAllAlwaysAdd();3008 } else {3009 AC.getCFGBuildOptions()3010 .setAlwaysAdd(Stmt::BinaryOperatorClass)3011 .setAlwaysAdd(Stmt::CompoundAssignOperatorClass)3012 .setAlwaysAdd(Stmt::BlockExprClass)3013 .setAlwaysAdd(Stmt::CStyleCastExprClass)3014 .setAlwaysAdd(Stmt::DeclRefExprClass)3015 .setAlwaysAdd(Stmt::ImplicitCastExprClass)3016 .setAlwaysAdd(Stmt::UnaryOperatorClass);3017 }3018 3019 // Install the logical handler.3020 std::optional<LogicalErrorHandler> LEH;3021 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {3022 LEH.emplace(S);3023 AC.getCFGBuildOptions().Observer = &*LEH;3024 }3025 3026 // Emit delayed diagnostics.3027 auto &PUDs = fscope->PossiblyUnreachableDiags;3028 emitPossiblyUnreachableDiags(S, AC, std::make_pair(PUDs.begin(), PUDs.end()));3029 3030 // Warning: check missing 'return'3031 if (P.enableCheckFallThrough) {3032 const CheckFallThroughDiagnostics &CD =3033 (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()3034 : (isa<CXXMethodDecl>(D) &&3035 cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call &&3036 cast<CXXMethodDecl>(D)->getParent()->isLambda())3037 ? CheckFallThroughDiagnostics::MakeForLambda()3038 : (fscope->isCoroutine()3039 ? CheckFallThroughDiagnostics::MakeForCoroutine(D)3040 : CheckFallThroughDiagnostics::MakeForFunction(S, D)));3041 CheckFallThroughForBody(S, D, Body, BlockType, CD, AC);3042 }3043 3044 // Warning: check for unreachable code3045 if (P.enableCheckUnreachable) {3046 // Only check for unreachable code on non-template instantiations.3047 // Different template instantiations can effectively change the control-flow3048 // and it is very difficult to prove that a snippet of code in a template3049 // is unreachable for all instantiations.3050 bool isTemplateInstantiation = false;3051 if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D))3052 isTemplateInstantiation = Function->isTemplateInstantiation();3053 if (!isTemplateInstantiation)3054 CheckUnreachable(S, AC);3055 }3056 3057 // Check for thread safety violations3058 if (P.enableThreadSafetyAnalysis) {3059 SourceLocation FL = AC.getDecl()->getLocation();3060 SourceLocation FEL = AC.getDecl()->getEndLoc();3061 threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);3062 if (!Diags.isIgnored(diag::warn_thread_safety_beta, D->getBeginLoc()))3063 Reporter.setIssueBetaWarnings(true);3064 if (!Diags.isIgnored(diag::warn_thread_safety_verbose, D->getBeginLoc()))3065 Reporter.setVerbose(true);3066 3067 threadSafety::runThreadSafetyAnalysis(AC, Reporter,3068 &S.ThreadSafetyDeclCache);3069 Reporter.emitDiagnostics();3070 }3071 3072 // Check for violations of consumed properties.3073 if (P.enableConsumedAnalysis) {3074 consumed::ConsumedWarningsHandler WarningHandler(S);3075 consumed::ConsumedAnalyzer Analyzer(WarningHandler);3076 Analyzer.run(AC);3077 }3078 3079 if (!Diags.isIgnored(diag::warn_uninit_var, D->getBeginLoc()) ||3080 !Diags.isIgnored(diag::warn_sometimes_uninit_var, D->getBeginLoc()) ||3081 !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getBeginLoc()) ||3082 !Diags.isIgnored(diag::warn_uninit_const_reference, D->getBeginLoc()) ||3083 !Diags.isIgnored(diag::warn_uninit_const_pointer, D->getBeginLoc())) {3084 if (CFG *cfg = AC.getCFG()) {3085 UninitValsDiagReporter reporter(S);3086 UninitVariablesAnalysisStats stats;3087 std::memset(&stats, 0, sizeof(UninitVariablesAnalysisStats));3088 runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC,3089 reporter, stats);3090 3091 if (S.CollectStats && stats.NumVariablesAnalyzed > 0) {3092 ++NumUninitAnalysisFunctions;3093 NumUninitAnalysisVariables += stats.NumVariablesAnalyzed;3094 NumUninitAnalysisBlockVisits += stats.NumBlockVisits;3095 MaxUninitAnalysisVariablesPerFunction =3096 std::max(MaxUninitAnalysisVariablesPerFunction,3097 stats.NumVariablesAnalyzed);3098 MaxUninitAnalysisBlockVisitsPerFunction =3099 std::max(MaxUninitAnalysisBlockVisitsPerFunction,3100 stats.NumBlockVisits);3101 }3102 }3103 }3104 3105 // TODO: Enable lifetime safety analysis for other languages once it is3106 // stable.3107 if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {3108 if (AC.getCFG()) {3109 lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);3110 lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter);3111 }3112 }3113 // Check for violations of "called once" parameter properties.3114 if (S.getLangOpts().ObjC && !S.getLangOpts().CPlusPlus &&3115 shouldAnalyzeCalledOnceParameters(Diags, D->getBeginLoc())) {3116 if (AC.getCFG()) {3117 CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);3118 checkCalledOnceParameters(3119 AC, Reporter,3120 shouldAnalyzeCalledOnceConventions(Diags, D->getBeginLoc()));3121 }3122 }3123 3124 bool FallThroughDiagFull =3125 !Diags.isIgnored(diag::warn_unannotated_fallthrough, D->getBeginLoc());3126 bool FallThroughDiagPerFunction = !Diags.isIgnored(3127 diag::warn_unannotated_fallthrough_per_function, D->getBeginLoc());3128 if (FallThroughDiagFull || FallThroughDiagPerFunction ||3129 fscope->HasFallthroughStmt) {3130 DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull);3131 }3132 3133 if (S.getLangOpts().ObjCWeak &&3134 !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, D->getBeginLoc()))3135 diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap());3136 3137 3138 // Check for infinite self-recursion in functions3139 if (!Diags.isIgnored(diag::warn_infinite_recursive_function,3140 D->getBeginLoc())) {3141 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {3142 checkRecursiveFunction(S, FD, Body, AC);3143 }3144 }3145 3146 // Check for throw out of non-throwing function.3147 if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getBeginLoc()))3148 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))3149 if (S.getLangOpts().CPlusPlus && !fscope->isCoroutine() && isNoexcept(FD))3150 checkThrowInNonThrowingFunc(S, FD, AC);3151 3152 // If none of the previous checks caused a CFG build, trigger one here3153 // for the logical error handler.3154 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {3155 AC.getCFG();3156 }3157 3158 // Clear any of our policy overrides.3159 clearOverrides();3160 3161 // Collect statistics about the CFG if it was built.3162 if (S.CollectStats && AC.isCFGBuilt()) {3163 ++NumFunctionsAnalyzed;3164 if (CFG *cfg = AC.getCFG()) {3165 // If we successfully built a CFG for this context, record some more3166 // detail information about it.3167 NumCFGBlocks += cfg->getNumBlockIDs();3168 MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,3169 cfg->getNumBlockIDs());3170 } else {3171 ++NumFunctionsWithBadCFGs;3172 }3173 }3174}3175 3176void clang::sema::AnalysisBasedWarnings::PrintStats() const {3177 llvm::errs() << "\n*** Analysis Based Warnings Stats:\n";3178 3179 unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;3180 unsigned AvgCFGBlocksPerFunction =3181 !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;3182 llvm::errs() << NumFunctionsAnalyzed << " functions analyzed ("3183 << NumFunctionsWithBadCFGs << " w/o CFGs).\n"3184 << " " << NumCFGBlocks << " CFG blocks built.\n"3185 << " " << AvgCFGBlocksPerFunction3186 << " average CFG blocks per function.\n"3187 << " " << MaxCFGBlocksPerFunction3188 << " max CFG blocks per function.\n";3189 3190 unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 03191 : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;3192 unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 03193 : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;3194 llvm::errs() << NumUninitAnalysisFunctions3195 << " functions analyzed for uninitialiazed variables\n"3196 << " " << NumUninitAnalysisVariables << " variables analyzed.\n"3197 << " " << AvgUninitVariablesPerFunction3198 << " average variables per function.\n"3199 << " " << MaxUninitAnalysisVariablesPerFunction3200 << " max variables per function.\n"3201 << " " << NumUninitAnalysisBlockVisits << " block visits.\n"3202 << " " << AvgUninitBlockVisitsPerFunction3203 << " average block visits per function.\n"3204 << " " << MaxUninitAnalysisBlockVisitsPerFunction3205 << " max block visits per function.\n";3206}3207