46#include "llvm/ADT/ArrayRef.h"
47#include "llvm/ADT/BitVector.h"
48#include "llvm/ADT/MapVector.h"
49#include "llvm/ADT/STLFunctionalExtras.h"
50#include "llvm/ADT/SmallVector.h"
51#include "llvm/ADT/StringRef.h"
69 UnreachableCodeHandler(
Sema &
s) : S(
s) {}
77 if (HasFallThroughAttr &&
84 if (PreviousSilenceableCondVal.
isValid() &&
86 PreviousSilenceableCondVal == SilenceableCondVal)
88 PreviousSilenceableCondVal = SilenceableCondVal;
90 unsigned diag = diag::warn_unreachable;
93 diag = diag::warn_unreachable_break;
96 diag = diag::warn_unreachable_return;
99 diag = diag::warn_unreachable_loop_increment;
105 S.
Diag(L, diag) << R1 << R2;
108 if (
Open.isValid()) {
112 S.
Diag(
Open, diag::note_unreachable_silence)
133 UnreachableCodeHandler UC(S);
143 LogicalErrorHandler(
Sema &S) : S(S) {}
145 static bool HasMacroID(
const Expr *
E) {
151 if (
const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt))
152 if (HasMacroID(SubExpr))
162 unsigned DiagID = isAlwaysTrue
163 ? diag::warn_tautological_negation_or_compare
164 : diag::warn_tautological_negation_and_compare;
174 S.
Diag(B->
getExprLoc(), diag::warn_tautological_overlap_comparison)
175 << DiagRange << isAlwaysTrue;
179 bool isAlwaysTrue)
override {
185 << DiagRange << isAlwaysTrue;
193 S.
Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;
198 return !Diags.
isIgnored(diag::warn_tautological_overlap_comparison,
Loc) ||
199 !Diags.
isIgnored(diag::warn_comparison_bitwise_or,
Loc) ||
200 !Diags.
isIgnored(diag::warn_tautological_negation_and_compare,
Loc);
214 for (
const auto &B :
Block) {
228 isa<TemplateSpecializationType>(NNS->getAsType())) {
247 bool foundRecursion =
false;
252 WorkList.push_back(&cfg->
getEntry());
254 while (!WorkList.empty()) {
259 if (!
Visited.insert(SuccBlock).second)
263 if (ExitID == SuccBlock->getBlockID())
268 foundRecursion =
true;
272 WorkList.push_back(SuccBlock);
276 return foundRecursion;
289 CFG *cfg = AC.getCFG();
312 Stack.push_back(&ThrowBlock);
315 while (!Stack.empty()) {
316 CFGBlock &UnwindBlock = *Stack.back();
319 for (
auto &Succ : UnwindBlock.
succs()) {
320 if (!Succ.isReachable() || Queued[Succ->getBlockID()])
327 dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
328 QualType Caught = Catch->getCaughtType();
335 Stack.push_back(Succ);
336 Queued[Succ->getBlockID()] =
true;
350 if (!Reachable[B->getBlockID()])
353 std::optional<CFGStmt> S =
E.getAs<
CFGStmt>();
356 if (
auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))
366 S.
Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
368 (isa<CXXDestructorDecl>(FD) ||
372 getAs<FunctionProtoType>())
374 << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec()
384 CFG *BodyCFG = AC.getCFG();
397 if (FPT->isNothrow() || FD->
hasAttr<NoThrowAttr>())
424 CFG *cfg = AC.getCFG();
433 bool AddEHEdges = AC.getAddEHEdges();
438 for (
const auto *B : *cfg) {
439 if (!live[B->getBlockID()]) {
440 if (B->pred_begin() == B->pred_end()) {
441 const Stmt *Term = B->getTerminatorStmt();
442 if (isa_and_nonnull<CXXTryStmt>(Term))
454 bool HasLiveReturn =
false;
455 bool HasFakeEdge =
false;
456 bool HasPlainEdge =
false;
457 bool HasAbnormalEdge =
false;
475 HasAbnormalEdge =
true;
484 for ( ; ri != re ; ++ri)
491 if (Term && (isa<CXXTryStmt>(Term) || isa<ObjCAtTryStmt>(Term))) {
492 HasAbnormalEdge =
true;
502 if (isa<ReturnStmt>(S) || isa<CoreturnStmt>(S)) {
503 HasLiveReturn =
true;
506 if (isa<ObjCAtThrowStmt>(S)) {
510 if (isa<CXXThrowExpr>(S)) {
514 if (isa<MSAsmStmt>(S)) {
517 HasLiveReturn =
true;
520 if (isa<CXXTryStmt>(S)) {
521 HasAbnormalEdge =
true;
525 HasAbnormalEdge =
true;
536 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
546struct CheckFallThroughDiagnostics {
547 unsigned diag_MaybeFallThrough_HasNoReturn;
548 unsigned diag_MaybeFallThrough_ReturnsNonVoid;
549 unsigned diag_AlwaysFallThrough_HasNoReturn;
550 unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
551 unsigned diag_NeverFallThroughOrReturn;
555 static CheckFallThroughDiagnostics MakeForFunction(
const Decl *
Func) {
556 CheckFallThroughDiagnostics
D;
557 D.FuncLoc =
Func->getLocation();
558 D.diag_MaybeFallThrough_HasNoReturn =
559 diag::warn_falloff_noreturn_function;
560 D.diag_MaybeFallThrough_ReturnsNonVoid =
561 diag::warn_maybe_falloff_nonvoid_function;
562 D.diag_AlwaysFallThrough_HasNoReturn =
563 diag::warn_falloff_noreturn_function;
564 D.diag_AlwaysFallThrough_ReturnsNonVoid =
565 diag::warn_falloff_nonvoid_function;
569 bool isVirtualMethod =
false;
571 isVirtualMethod = Method->isVirtual();
579 D.diag_NeverFallThroughOrReturn =
580 diag::warn_suggest_noreturn_function;
582 D.diag_NeverFallThroughOrReturn = 0;
588 static CheckFallThroughDiagnostics MakeForCoroutine(
const Decl *
Func) {
589 CheckFallThroughDiagnostics
D;
590 D.FuncLoc =
Func->getLocation();
591 D.diag_MaybeFallThrough_HasNoReturn = 0;
592 D.diag_MaybeFallThrough_ReturnsNonVoid =
593 diag::warn_maybe_falloff_nonvoid_coroutine;
594 D.diag_AlwaysFallThrough_HasNoReturn = 0;
595 D.diag_AlwaysFallThrough_ReturnsNonVoid =
596 diag::warn_falloff_nonvoid_coroutine;
597 D.diag_NeverFallThroughOrReturn = 0;
598 D.funMode = Coroutine;
602 static CheckFallThroughDiagnostics MakeForBlock() {
603 CheckFallThroughDiagnostics
D;
604 D.diag_MaybeFallThrough_HasNoReturn =
605 diag::err_noreturn_block_has_return_expr;
606 D.diag_MaybeFallThrough_ReturnsNonVoid =
607 diag::err_maybe_falloff_nonvoid_block;
608 D.diag_AlwaysFallThrough_HasNoReturn =
609 diag::err_noreturn_block_has_return_expr;
610 D.diag_AlwaysFallThrough_ReturnsNonVoid =
611 diag::err_falloff_nonvoid_block;
612 D.diag_NeverFallThroughOrReturn = 0;
617 static CheckFallThroughDiagnostics MakeForLambda() {
618 CheckFallThroughDiagnostics
D;
619 D.diag_MaybeFallThrough_HasNoReturn =
620 diag::err_noreturn_lambda_has_return_expr;
621 D.diag_MaybeFallThrough_ReturnsNonVoid =
622 diag::warn_maybe_falloff_nonvoid_lambda;
623 D.diag_AlwaysFallThrough_HasNoReturn =
624 diag::err_noreturn_lambda_has_return_expr;
625 D.diag_AlwaysFallThrough_ReturnsNonVoid =
626 diag::warn_falloff_nonvoid_lambda;
627 D.diag_NeverFallThroughOrReturn = 0;
633 bool HasNoReturn)
const {
634 if (funMode == Function) {
635 return (ReturnsVoid ||
636 D.isIgnored(diag::warn_maybe_falloff_nonvoid_function,
639 D.isIgnored(diag::warn_noreturn_function_has_return_expr,
642 D.isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));
644 if (funMode == Coroutine) {
645 return (ReturnsVoid ||
646 D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, FuncLoc) ||
647 D.isIgnored(diag::warn_maybe_falloff_nonvoid_coroutine,
652 return ReturnsVoid && !HasNoReturn;
664 const CheckFallThroughDiagnostics &CD,
668 bool ReturnsVoid =
false;
669 bool HasNoReturn =
false;
672 if (
const auto *FD = dyn_cast<FunctionDecl>(
D)) {
673 if (
const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
674 ReturnsVoid = CBody->getFallthroughHandler() !=
nullptr;
676 ReturnsVoid = FD->getReturnType()->isVoidType();
677 HasNoReturn = FD->isNoReturn();
679 else if (
const auto *MD = dyn_cast<ObjCMethodDecl>(
D)) {
680 ReturnsVoid = MD->getReturnType()->isVoidType();
681 HasNoReturn = MD->hasAttr<NoReturnAttr>();
683 else if (isa<BlockDecl>(
D)) {
686 if (FT->getReturnType()->isVoidType())
688 if (FT->getNoReturnAttr())
696 if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
717 EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);
718 else if (!ReturnsVoid)
719 EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);
723 EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);
724 else if (!ReturnsVoid)
725 EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
728 if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
730 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
732 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
734 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
759 : Inherited(Context), FoundReference(
false), Needle(Needle) {}
761 void VisitExpr(
const Expr *
E) {
766 Inherited::VisitExpr(
E);
771 FoundReference =
true;
776 bool doesContainReference()
const {
return FoundReference; }
784 S.
Diag(VD->
getLocation(), diag::note_block_var_fixit_add_initialization)
813 const Stmt *Else,
bool CondVal,
837 bool IsCapturedByBlock) {
838 bool Diagnosed =
false;
871 const Stmt *Term = I->Terminator;
881 int RemoveDiagKind = -1;
882 const char *FixitStr =
883 S.
getLangOpts().CPlusPlus ? (I->Output ?
"true" :
"false")
884 : (I->Output ?
"1" :
"0");
887 switch (Term ? Term->
getStmtClass() : Stmt::DeclStmtClass) {
894 case Stmt::IfStmtClass: {
895 const IfStmt *IS = cast<IfStmt>(Term);
901 I->Output, Fixit1, Fixit2);
904 case Stmt::ConditionalOperatorClass: {
911 I->Output, Fixit1, Fixit2);
914 case Stmt::BinaryOperatorClass: {
922 if ((BO->
getOpcode() == BO_LAnd && I->Output) ||
923 (BO->
getOpcode() == BO_LOr && !I->Output))
934 case Stmt::WhileStmtClass:
937 Range = cast<WhileStmt>(Term)->getCond()->getSourceRange();
941 case Stmt::ForStmtClass:
944 Range = cast<ForStmt>(Term)->getCond()->getSourceRange();
951 case Stmt::CXXForRangeStmtClass:
952 if (I->Output == 1) {
960 Range = cast<CXXForRangeStmt>(Term)->getRangeInit()->getSourceRange();
964 case Stmt::DoStmtClass:
967 Range = cast<DoStmt>(Term)->getCond()->getSourceRange();
973 case Stmt::CaseStmtClass:
976 Range = cast<CaseStmt>(Term)->getLHS()->getSourceRange();
978 case Stmt::DefaultStmtClass:
981 Range = cast<DefaultStmt>(Term)->getDefaultLoc();
986 << VD->
getDeclName() << IsCapturedByBlock << DiagKind
987 << Str << I->Output <<
Range;
990 if (RemoveDiagKind != -1)
992 << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
1018 bool alwaysReportSelfInit =
false) {
1032 if (!alwaysReportSelfInit && DRE ==
Initializer->IgnoreParenImpCasts())
1035 ContainsReference CR(S.
Context, DRE);
1037 if (CR.doesContainReference()) {
1038 S.
Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
1049 diag::warn_uninit_byref_blockvar_captured_by_block)
1069 FallthroughMapper(
Sema &S) : FoundSwitchStatements(
false), S(S) {
1070 ShouldWalkTypesOfTypeLocs =
false;
1073 bool foundSwitchStatements()
const {
return FoundSwitchStatements; }
1076 bool Found = FallthroughStmts.erase(
Stmt);
1083 const AttrStmts &getFallthroughStmts()
const {
return FallthroughStmts; }
1085 void fillReachableBlocks(
CFG *Cfg) {
1086 assert(ReachableBlocks.empty() &&
"ReachableBlocks already filled");
1087 std::deque<const CFGBlock *> BlockQueue;
1089 ReachableBlocks.insert(&Cfg->
getEntry());
1090 BlockQueue.push_back(&Cfg->
getEntry());
1095 for (
const auto *B : *Cfg) {
1096 const Stmt *L = B->getLabel();
1097 if (isa_and_nonnull<SwitchCase>(L) && ReachableBlocks.insert(B).second)
1098 BlockQueue.push_back(B);
1101 while (!BlockQueue.empty()) {
1103 BlockQueue.pop_front();
1105 if (B && ReachableBlocks.insert(B).second)
1106 BlockQueue.push_back(B);
1111 bool checkFallThroughIntoBlock(
const CFGBlock &B,
int &AnnotatedCnt,
1112 bool IsTemplateInstantiation) {
1113 assert(!ReachableBlocks.empty() &&
"ReachableBlocks empty");
1115 int UnannotatedCnt = 0;
1119 while (!BlockQueue.empty()) {
1121 BlockQueue.pop_front();
1125 const Stmt *Term =
P->getTerminatorStmt();
1126 if (isa_and_nonnull<SwitchStmt>(Term))
1129 const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(
P->getLabel());
1133 const LabelStmt *L = dyn_cast_or_null<LabelStmt>(
P->getLabel());
1137 if (!ReachableBlocks.count(
P)) {
1138 for (
const CFGElement &Elem : llvm::reverse(*
P)) {
1139 if (std::optional<CFGStmt> CS = Elem.getAs<
CFGStmt>()) {
1140 if (
const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
1144 if (!IsTemplateInstantiation)
1145 S.
Diag(AS->getBeginLoc(),
1146 diag::warn_unreachable_fallthrough_attr);
1147 markFallthroughVisited(AS);
1167 markFallthroughVisited(AS);
1174 std::copy(
P->pred_begin(),
P->pred_end(),
1175 std::back_inserter(BlockQueue));
1181 return !!UnannotatedCnt;
1185 if (asFallThroughAttr(S))
1186 FallthroughStmts.insert(S);
1190 bool VisitSwitchStmt(
SwitchStmt *S)
override {
1191 FoundSwitchStatements =
true;
1200 bool TraverseLambdaExpr(
LambdaExpr *LE)
override {
1202 for (
const auto C : zip(
LE->captures(),
LE->capture_inits()))
1210 if (
const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
1211 if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs()))
1220 for (
const CFGElement &Elem : llvm::reverse(B))
1221 if (std::optional<CFGStmt> CS = Elem.getAs<
CFGStmt>())
1222 return CS->getStmt();
1233 bool FoundSwitchStatements;
1234 AttrStmts FallthroughStmts;
1243 tok::l_square, tok::l_square,
1245 tok::r_square, tok::r_square
1251 tok::r_square, tok::r_square
1256 StringRef MacroName;
1257 if (PreferClangAttr)
1259 if (MacroName.empty())
1261 if (MacroName.empty() && !PreferClangAttr)
1263 if (MacroName.empty()) {
1264 if (!PreferClangAttr)
1265 MacroName =
"[[fallthrough]]";
1267 MacroName =
"[[clang::fallthrough]]";
1269 MacroName =
"__attribute__((fallthrough))";
1276 FallthroughMapper FM(S);
1277 FM.TraverseStmt(AC.getBody());
1279 if (!FM.foundSwitchStatements())
1282 if (PerFunction && FM.getFallthroughStmts().empty())
1285 CFG *Cfg = AC.getCFG();
1290 FM.fillReachableBlocks(Cfg);
1292 for (
const CFGBlock *B : llvm::reverse(*Cfg)) {
1295 if (!isa_and_nonnull<SwitchCase>(
Label))
1300 bool IsTemplateInstantiation =
false;
1302 IsTemplateInstantiation =
Function->isTemplateInstantiation();
1303 if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,
1304 IsTemplateInstantiation))
1308 PerFunction ? diag::warn_unannotated_fallthrough_per_function
1309 : diag::warn_unannotated_fallthrough);
1311 if (!AnnotatedCnt) {
1322 if (!(B->
empty() && isa_and_nonnull<BreakStmt>(Term))) {
1326 TextToInsert +=
"; ";
1327 S.
Diag(L, diag::note_insert_fallthrough_fixit)
1328 << AnnotationSpelling
1331 S.
Diag(L, diag::note_insert_break_fixit)
1336 for (
const auto *F : FM.getFallthroughStmts())
1337 S.
Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement);
1345 switch (S->getStmtClass()) {
1346 case Stmt::ForStmtClass:
1347 case Stmt::WhileStmtClass:
1348 case Stmt::CXXForRangeStmtClass:
1349 case Stmt::ObjCForCollectionStmtClass:
1351 case Stmt::DoStmtClass: {
1353 if (!cast<DoStmt>(S)->getCond()->
EvaluateAsInt(Result, Ctx))
1355 return Result.Val.getInt().getBoolValue();
1372 typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
1381 for (WeakObjectUseMap::const_iterator I = WeakMap.begin(),
E = WeakMap.end();
1383 const WeakUseVector &Uses = I->second;
1386 WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
1387 for ( ; UI != UE; ++UI) {
1400 if (UI == Uses.begin()) {
1401 WeakUseVector::const_iterator UI2 = UI;
1402 for (++UI2; UI2 != UE; ++UI2)
1403 if (UI2->isUnsafe())
1407 if (!
isInLoop(Ctx, PM, UI->getUseExpr()))
1410 const WeakObjectProfileTy &Profile = I->first;
1411 if (!Profile.isExactProfile())
1416 Base = Profile.getProperty();
1417 assert(
Base &&
"A profile always has a base or property.");
1419 if (
const VarDecl *BaseVar = dyn_cast<VarDecl>(
Base))
1420 if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(
Base))
1425 UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
1428 if (UsesByStmt.empty())
1433 llvm::sort(UsesByStmt,
1434 [&
SM](
const StmtUsesPair &LHS,
const StmtUsesPair &RHS) {
1436 RHS.first->getBeginLoc());
1451 if (isa<sema::BlockScopeInfo>(CurFn))
1452 FunctionKind =
Block;
1453 else if (isa<sema::LambdaScopeInfo>(CurFn))
1454 FunctionKind = Lambda;
1455 else if (isa<ObjCMethodDecl>(
D))
1456 FunctionKind = Method;
1461 for (
const auto &
P : UsesByStmt) {
1462 const Stmt *FirstRead =
P.first;
1463 const WeakObjectProfileTy &Key =
P.second->first;
1464 const WeakUseVector &Uses =
P.second->second;
1472 if (Key.isExactProfile())
1473 DiagKind = diag::warn_arc_repeated_use_of_weak;
1475 DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
1487 const NamedDecl *KeyProp = Key.getProperty();
1488 if (isa<VarDecl>(KeyProp))
1490 else if (isa<ObjCPropertyDecl>(KeyProp))
1492 else if (isa<ObjCMethodDecl>(KeyProp))
1493 ObjectKind = ImplicitProperty;
1494 else if (isa<ObjCIvarDecl>(KeyProp))
1497 llvm_unreachable(
"Unexpected weak object kind!");
1502 if (Prop->hasAttr<IBOutletAttr>())
1507 <<
int(ObjectKind) << KeyProp <<
int(FunctionKind)
1511 for (
const auto &Use : Uses) {
1512 if (Use.getUseExpr() == FirstRead)
1514 S.
Diag(Use.getUseExpr()->getBeginLoc(),
1515 diag::note_arc_weak_also_accessed_here)
1516 << Use.getUseExpr()->getSourceRange();
1524typedef std::pair<PartialDiagnosticAt, OptionalNotes>
DelayedDiag;
1525typedef std::list<DelayedDiag>
DiagList;
1527struct SortDiagBySourceLocation {
1531 bool operator()(
const DelayedDiag &left,
const DelayedDiag &right) {
1534 return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
1544 typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
1548 typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
1550 UsesMap constRefUses;
1553 UninitValsDiagReporter(
Sema &S) : S(S) {}
1556 MappedType &getUses(UsesMap &um,
const VarDecl *vd) {
1557 MappedType &
V = um[vd];
1558 if (!
V.getPointer())
1559 V.setPointer(
new UsesVec());
1565 getUses(uses, vd).getPointer()->push_back(use);
1570 getUses(constRefUses, vd).getPointer()->push_back(use);
1574 getUses(uses, vd).setInt(
true);
1575 getUses(constRefUses, vd).setInt(
true);
1579 for (
const auto &
P : uses) {
1581 const MappedType &
V =
P.second;
1583 UsesVec *vec =
V.getPointer();
1584 bool hasSelfInit =
V.getInt();
1589 if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
1605 for (
const auto &
U : *vec) {
1623 for (
const auto &
P : constRefUses) {
1625 const MappedType &
V =
P.second;
1627 UsesVec *vec =
V.getPointer();
1628 bool hasSelfInit =
V.getInt();
1630 if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
1636 for (
const auto &
U : *vec) {
1646 constRefUses.clear();
1650 static bool hasAlwaysUninitializedUse(
const UsesVec* vec) {
1651 return llvm::any_of(*vec, [](
const UninitUse &
U) {
1660class CalledOnceInterProceduralData {
1665 DelayedBlockWarnings[
Block].emplace_back(std::move(
Warning));
1670 S.
Diag(Delayed.first, Delayed.second);
1672 discardWarnings(
Block);
1676 DelayedBlockWarnings.erase(
Block);
1681 llvm::DenseMap<const BlockDecl *, DelayedDiagnostics> DelayedBlockWarnings;
1686 CalledOnceCheckReporter(
Sema &S, CalledOnceInterProceduralData &Data)
1689 const Expr *PrevCall,
bool IsCompletionHandler,
1690 bool Poised)
override {
1691 auto DiagToReport = IsCompletionHandler
1692 ? diag::warn_completion_handler_called_twice
1693 : diag::warn_called_once_gets_called_twice;
1695 S.
Diag(PrevCall->
getBeginLoc(), diag::note_called_once_gets_called_twice)
1700 bool IsCompletionHandler)
override {
1701 auto DiagToReport = IsCompletionHandler
1702 ? diag::warn_completion_handler_never_called
1703 : diag::warn_called_once_never_called;
1710 bool IsCalledDirectly,
1711 bool IsCompletionHandler)
override {
1712 auto DiagToReport = IsCompletionHandler
1713 ? diag::warn_completion_handler_never_called_when
1714 : diag::warn_called_once_never_called_when;
1718 << (
unsigned)Reason);
1720 if (
const auto *
Block = dyn_cast<BlockDecl>(Function)) {
1730 bool IsCompletionHandler)
override {
1731 auto DiagToReport = IsCompletionHandler
1732 ? diag::warn_completion_handler_never_called
1733 : diag::warn_called_once_never_called;
1749 CalledOnceInterProceduralData &
Data;
1752constexpr unsigned CalledOnceWarnings[] = {
1753 diag::warn_called_once_never_called,
1754 diag::warn_called_once_never_called_when,
1755 diag::warn_called_once_gets_called_twice};
1757constexpr unsigned CompletionHandlerWarnings[]{
1758 diag::warn_completion_handler_never_called,
1759 diag::warn_completion_handler_never_called_when,
1760 diag::warn_completion_handler_called_twice};
1765 return llvm::any_of(DiagIDs, [&Diags, At](
unsigned DiagID) {
1772 return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);
1777 return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||
1778 shouldAnalyzeCalledOnceConventions(Diags, At);
1786namespace threadSafety {
1797 if (Verbose && CurrentFunction) {
1799 S.
PDiag(diag::note_thread_warning_in_fun)
1800 << CurrentFunction);
1808 if (Verbose && CurrentFunction) {
1810 S.
PDiag(diag::note_thread_warning_in_fun)
1811 << CurrentFunction);
1812 ONS.push_back(std::move(FNote));
1820 ONS.push_back(Note1);
1821 ONS.push_back(Note2);
1822 if (Verbose && CurrentFunction) {
1824 S.
PDiag(diag::note_thread_warning_in_fun)
1825 << CurrentFunction);
1826 ONS.push_back(std::move(FNote));
1834 LocLocked, S.
PDiag(diag::note_locked_here) << Kind))
1842 LocUnlocked, S.
PDiag(diag::note_unlocked_here) << Kind))
1850 S.
PDiag(diag::note_managed_mismatch_here_for_param)))
1856 : S(S), FunLocation(FL), FunEndLocation(FEL),
1857 CurrentFunction(nullptr), Verbose(
false) {}
1859 void setVerbose(
bool b) { Verbose =
b; }
1867 for (
const auto &
Diag : Warnings) {
1869 for (
const auto &
Note :
Diag.second)
1875 Name scopeName, StringRef Kind,
1876 Name expected, Name actual)
override {
1878 S.
PDiag(diag::warn_unmatched_underlying_mutexes)
1879 << Kind << scopeName << expected << actual);
1880 Warnings.emplace_back(std::move(
Warning),
1881 makeManagedMismatchNoteForParam(DLoc));
1887 Name expected)
override {
1889 Loc, S.
PDiag(diag::warn_expect_more_underlying_mutexes)
1890 << Kind << scopeName << expected);
1891 Warnings.emplace_back(std::move(
Warning),
1892 makeManagedMismatchNoteForParam(DLoc));
1898 Name actual)
override {
1900 Loc, S.
PDiag(diag::warn_expect_fewer_underlying_mutexes)
1901 << Kind << scopeName << actual);
1902 Warnings.emplace_back(std::move(
Warning),
1903 makeManagedMismatchNoteForParam(DLoc));
1909 Warnings.emplace_back(std::move(
Warning), getNotes());
1917 << Kind << LockName);
1918 Warnings.emplace_back(std::move(
Warning),
1919 makeUnlockedHereNote(LocPreviousUnlock, Kind));
1922 void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
1927 LocUnlock = FunLocation;
1929 LocUnlock, S.
PDiag(diag::warn_unlock_kind_mismatch)
1930 << Kind << LockName << Received <<
Expected);
1931 Warnings.emplace_back(std::move(
Warning),
1932 makeLockedHereNote(LocLocked, Kind));
1935 void handleDoubleLock(StringRef Kind, Name LockName,
SourceLocation LocLocked,
1938 LocDoubleLock = FunLocation;
1940 << Kind << LockName);
1941 Warnings.emplace_back(std::move(
Warning),
1942 makeLockedHereNote(LocLocked, Kind));
1945 void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
1949 unsigned DiagID = 0;
1952 DiagID = diag::warn_lock_some_predecessors;
1955 DiagID = diag::warn_expecting_lock_held_on_loop;
1958 DiagID = diag::warn_no_unlock;
1961 DiagID = diag::warn_expecting_locked;
1965 LocEndOfScope = FunEndLocation;
1969 Warnings.emplace_back(std::move(
Warning),
1970 makeLockedHereNote(LocLocked, Kind));
1973 void handleExclusiveAndShared(StringRef Kind, Name LockName,
1977 S.
PDiag(diag::warn_lock_exclusive_and_shared)
1978 << Kind << LockName);
1980 << Kind << LockName);
1981 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
1987 "Only works for variables");
1989 diag::warn_variable_requires_any_lock:
1990 diag::warn_var_deref_requires_any_lock;
1993 Warnings.emplace_back(std::move(
Warning), getNotes());
1996 void handleMutexNotHeld(StringRef Kind,
const NamedDecl *
D,
1999 Name *PossibleMatch)
override {
2000 unsigned DiagID = 0;
2001 if (PossibleMatch) {
2004 DiagID = diag::warn_variable_requires_lock_precise;
2007 DiagID = diag::warn_var_deref_requires_lock_precise;
2010 DiagID = diag::warn_fun_requires_lock_precise;
2013 DiagID = diag::warn_guarded_pass_by_reference;
2016 DiagID = diag::warn_pt_guarded_pass_by_reference;
2019 DiagID = diag::warn_guarded_return_by_reference;
2022 DiagID = diag::warn_pt_guarded_return_by_reference;
2032 S.
PDiag(diag::note_guarded_by_declared_here)
2033 <<
D->getDeclName());
2034 Warnings.emplace_back(std::move(
Warning), getNotes(
Note, VNote));
2036 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2040 DiagID = diag::warn_variable_requires_lock;
2043 DiagID = diag::warn_var_deref_requires_lock;
2046 DiagID = diag::warn_fun_requires_lock;
2049 DiagID = diag::warn_guarded_pass_by_reference;
2052 DiagID = diag::warn_pt_guarded_pass_by_reference;
2055 DiagID = diag::warn_guarded_return_by_reference;
2058 DiagID = diag::warn_pt_guarded_return_by_reference;
2066 S.
PDiag(diag::note_guarded_by_declared_here));
2067 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2069 Warnings.emplace_back(std::move(
Warning), getNotes());
2073 void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
2076 S.
PDiag(diag::warn_acquire_requires_negative_cap)
2077 << Kind << LockName << Neg);
2078 Warnings.emplace_back(std::move(
Warning), getNotes());
2081 void handleNegativeNotHeld(
const NamedDecl *
D, Name LockName,
2084 Loc, S.
PDiag(diag::warn_fun_requires_negative_cap) <<
D << LockName);
2085 Warnings.emplace_back(std::move(
Warning), getNotes());
2088 void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
2091 << Kind << FunName << LockName);
2092 Warnings.emplace_back(std::move(
Warning), getNotes());
2095 void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
2098 S.
PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
2099 Warnings.emplace_back(std::move(
Warning), getNotes());
2104 S.
PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
2105 Warnings.emplace_back(std::move(
Warning), getNotes());
2109 CurrentFunction = FD;
2113 CurrentFunction =
nullptr;
2127class ConsumedWarningsHandler :
public ConsumedWarningsHandlerBase {
2134 ConsumedWarningsHandler(
Sema &S) : S(S) {}
2138 for (
const auto &
Diag : Warnings) {
2140 for (
const auto &
Note :
Diag.second)
2146 StringRef VariableName)
override {
2154 StringRef VariableName,
2155 StringRef ExpectedState,
2156 StringRef ObservedState)
override {
2159 diag::warn_param_return_typestate_mismatch) << VariableName <<
2160 ExpectedState << ObservedState);
2166 StringRef ObservedState)
override {
2169 diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
2175 StringRef TypeName)
override {
2177 diag::warn_return_typestate_for_unconsumable_type) << TypeName);
2183 StringRef ObservedState)
override {
2186 diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
2191 void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
2195 diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
2200 void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
2204 MethodName << VariableName << State);
2220 bool SuggestSuggestions;
2224 std::string listVariableGroupAsString(
2226 if (VarGroupForVD.size() <= 1)
2229 std::vector<StringRef> VarNames;
2230 auto PutInQuotes = [](StringRef S) -> std::string {
2231 return "'" + S.str() +
"'";
2234 for (
auto *
V : VarGroupForVD) {
2237 VarNames.push_back(
V->getName());
2239 if (VarNames.size() == 1) {
2240 return PutInQuotes(VarNames[0]);
2242 if (VarNames.size() == 2) {
2243 return PutInQuotes(VarNames[0]) +
" and " + PutInQuotes(VarNames[1]);
2245 assert(VarGroupForVD.size() > 3);
2246 const unsigned N = VarNames.size() -
2248 std::string AllVars =
"";
2250 for (
unsigned I = 0; I < N; ++I)
2251 AllVars.append(PutInQuotes(VarNames[I]) +
", ");
2252 AllVars.append(PutInQuotes(VarNames[N]) +
", and " +
2253 PutInQuotes(VarNames[N + 1]));
2258 UnsafeBufferUsageReporter(
Sema &S,
bool SuggestSuggestions)
2259 : S(S), SuggestSuggestions(SuggestSuggestions) {}
2265 unsigned MsgParam = 0;
2267 if (
const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
2268 Loc = ASE->getBase()->getExprLoc();
2269 Range = ASE->getBase()->getSourceRange();
2271 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
2273 if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
2274 Op == BO_SubAssign) {
2275 if (BO->getRHS()->getType()->isIntegerType()) {
2276 Loc = BO->getLHS()->getExprLoc();
2277 Range = BO->getLHS()->getSourceRange();
2279 Loc = BO->getRHS()->getExprLoc();
2280 Range = BO->getRHS()->getSourceRange();
2284 }
else if (
const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
2286 if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
2288 Loc = UO->getSubExpr()->getExprLoc();
2289 Range = UO->getSubExpr()->getSourceRange();
2293 if (isa<CallExpr>(Operation) || isa<CXXConstructExpr>(Operation)) {
2295 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2297 }
else if (isa<MemberExpr>(Operation)) {
2299 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2300 auto *ME = cast<MemberExpr>(Operation);
2301 D = ME->getMemberDecl();
2303 }
else if (
const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) {
2304 QualType destType = ECE->getType();
2305 bool destTypeComplete =
true;
2307 if (!isa<PointerType>(destType))
2311 destTypeComplete =
D->isCompleteDefinition();
2315 if (destTypeComplete) {
2317 QualType srcType = ECE->getSubExpr()->getType();
2327 if (
const auto *CE = dyn_cast<CXXMemberCallExpr>(
2328 ECE->getSubExpr()->IgnoreParens())) {
2329 D = CE->getMethodDecl();
2340 if (IsRelatedToDecl) {
2341 assert(!SuggestSuggestions &&
2342 "Variables blamed for unsafe buffer usage without suggestions!");
2343 S.
Diag(
Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2346 S.
Diag(
Loc, diag::warn_unsafe_buffer_operation)
2347 << MsgParam <<
D <<
Range;
2349 S.
Diag(
Loc, diag::warn_unsafe_buffer_operation) << MsgParam <<
Range;
2351 if (SuggestSuggestions) {
2352 S.
Diag(
Loc, diag::note_safe_buffer_usage_suggestions_disabled);
2359 const Expr *UnsafeArg =
nullptr)
override {
2360 S.
Diag(
Call->getBeginLoc(), diag::warn_unsafe_buffer_libc_call)
2361 <<
Call->getDirectCallee()
2362 <<
Call->getSourceRange();
2363 if (PrintfInfo > 0) {
2365 UnsafeArg ? UnsafeArg->getSourceRange() :
Call->getSourceRange();
2366 S.
Diag(R.
getBegin(), diag::note_unsafe_buffer_printf_call)
2372 bool IsRelatedToDecl,
2376 unsigned MsgParam = 0;
2380 const auto *CtorExpr = cast<CXXConstructExpr>(Operation);
2381 Loc = CtorExpr->getLocation();
2383 S.
Diag(
Loc, diag::warn_unsafe_buffer_usage_in_container);
2384 if (IsRelatedToDecl) {
2385 assert(!SuggestSuggestions &&
2386 "Variables blamed for unsafe buffer usage without suggestions!");
2387 S.
Diag(
Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2393 FixItList &&Fixes,
const Decl *
D,
2395 assert(!SuggestSuggestions &&
2396 "Unsafe buffer usage fixits displayed without suggestions!");
2400 if (!Fixes.empty()) {
2401 assert(isa<NamedDecl>(
D) &&
2402 "Fix-its are generated only for `NamedDecl`s");
2404 bool BriefMsg =
false;
2409 unsigned FixItStrategy = 0;
2418 assert(
false &&
"We support only std::span and std::array");
2423 BriefMsg ? diag::note_unsafe_buffer_variable_fixit_together
2424 : diag::note_unsafe_buffer_variable_fixit_group);
2427 FD << listVariableGroupAsString(
Variable, VarGroupForVD)
2428 << (VarGroupForVD.size() > 1) << ND;
2429 for (
const auto &F : Fixes) {
2437 S.
Diag(
Note.first, diag::note_safe_buffer_debug_mode) <<
Note.second;
2458 StringRef WSSuffix =
"")
const override {
2460 TokenValue ClangUnsafeBufferUsageTokens[] = {
2469 StringRef MacroName;
2473 if (MacroName.empty())
2474 MacroName =
"[[clang::unsafe_buffer_usage]]";
2475 return MacroName.str() + WSSuffix.str();
2486 enableCheckFallThrough = 1;
2487 enableCheckUnreachable = 0;
2488 enableThreadSafetyAnalysis = 0;
2489 enableConsumedAnalysis = 0;
2516 NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),
2517 MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),
2518 NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
2519 NumUninitAnalysisBlockVisits(0),
2520 MaxUninitAnalysisBlockVisitsPerFunction(0) {
2522 using namespace diag;
2525 DefaultPolicy.enableCheckUnreachable =
2528 isEnabled(
D, warn_unreachable_loop_increment);
2530 DefaultPolicy.enableThreadSafetyAnalysis =
isEnabled(
D, warn_double_lock);
2532 DefaultPolicy.enableConsumedAnalysis =
2548 llvm::function_ref<void(
const Decl *)> Callback;
2552 : Callback(Callback) {
2553 ShouldVisitTemplateInstantiations =
true;
2554 ShouldVisitImplicitCode =
false;
2558 if (cast<DeclContext>(
Node)->isDependentContext())
2563 if (
Node->doesThisDeclarationHaveABody())
2569 if (cast<DeclContext>(
Node)->isDependentContext())
2576 if (cast<DeclContext>(
Node)->isDependentContext())
2578 if (
Node->hasBody())
2584 return VisitFunctionDecl(
Node->getCallOperator());
2602 bool UnsafeBufferUsageCanEmitSuggestions = S.
getLangOpts().CPlusPlus20;
2603 bool UnsafeBufferUsageShouldEmitSuggestions =
2604 UnsafeBufferUsageCanEmitSuggestions &&
2605 DiagOpts.ShowSafeBufferUsageSuggestions;
2606 bool UnsafeBufferUsageShouldSuggestSuggestions =
2607 UnsafeBufferUsageCanEmitSuggestions &&
2608 !DiagOpts.ShowSafeBufferUsageSuggestions;
2609 UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions);
2612 auto CallAnalyzers = [&](
const Decl *
Node) ->
void {
2614 if (!Diags.
isIgnored(diag::warn_unsafe_buffer_operation,
2615 Node->getBeginLoc()) ||
2616 !Diags.
isIgnored(diag::warn_unsafe_buffer_variable,
2617 Node->getBeginLoc()) ||
2618 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2619 Node->getBeginLoc()) ||
2620 !Diags.
isIgnored(diag::warn_unsafe_buffer_libc_call,
2621 Node->getBeginLoc())) {
2623 UnsafeBufferUsageShouldEmitSuggestions);
2632 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2659 if (cast<DeclContext>(
D)->isDependentContext())
2676 AC.getCFGBuildOptions().PruneTriviallyFalseEdges =
true;
2677 AC.getCFGBuildOptions().AddEHEdges =
false;
2678 AC.getCFGBuildOptions().AddInitializers =
true;
2679 AC.getCFGBuildOptions().AddImplicitDtors =
true;
2680 AC.getCFGBuildOptions().AddTemporaryDtors =
true;
2681 AC.getCFGBuildOptions().AddCXXNewAllocator =
false;
2682 AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors =
true;
2690 if (
P.enableCheckUnreachable ||
P.enableThreadSafetyAnalysis ||
2691 P.enableConsumedAnalysis) {
2693 AC.getCFGBuildOptions().setAllAlwaysAdd();
2696 AC.getCFGBuildOptions()
2697 .setAlwaysAdd(Stmt::BinaryOperatorClass)
2698 .setAlwaysAdd(Stmt::CompoundAssignOperatorClass)
2699 .setAlwaysAdd(Stmt::BlockExprClass)
2700 .setAlwaysAdd(Stmt::CStyleCastExprClass)
2701 .setAlwaysAdd(Stmt::DeclRefExprClass)
2702 .setAlwaysAdd(Stmt::ImplicitCastExprClass)
2703 .setAlwaysAdd(Stmt::UnaryOperatorClass);
2707 std::optional<LogicalErrorHandler> LEH;
2708 if (LogicalErrorHandler::hasActiveDiagnostics(Diags,
D->
getBeginLoc())) {
2710 AC.getCFGBuildOptions().Observer = &*LEH;
2715 bool analyzed =
false;
2719 for (
const Stmt *S :
D.Stmts)
2720 AC.registerForcedBlockExpression(S);
2726 bool AllReachable =
true;
2727 for (
const Stmt *S :
D.Stmts) {
2728 const CFGBlock *block = AC.getBlockForRegisteredExpression(S);
2730 AC.getCFGReachablityAnalysis();
2736 if (!cra->
isReachable(&AC.getCFG()->getEntry(), block)) {
2737 AllReachable =
false;
2755 if (
P.enableCheckFallThrough) {
2756 const CheckFallThroughDiagnostics &CD =
2758 ? CheckFallThroughDiagnostics::MakeForBlock()
2759 : (isa<CXXMethodDecl>(
D) &&
2760 cast<CXXMethodDecl>(
D)->getOverloadedOperator() == OO_Call &&
2761 cast<CXXMethodDecl>(
D)->getParent()->isLambda())
2762 ? CheckFallThroughDiagnostics::MakeForLambda()
2764 ? CheckFallThroughDiagnostics::MakeForCoroutine(
D)
2765 : CheckFallThroughDiagnostics::MakeForFunction(
D)));
2770 if (
P.enableCheckUnreachable) {
2783 if (
P.enableThreadSafetyAnalysis) {
2786 threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
2788 Reporter.setIssueBetaWarnings(
true);
2790 Reporter.setVerbose(
true);
2794 Reporter.emitDiagnostics();
2798 if (
P.enableConsumedAnalysis) {
2799 consumed::ConsumedWarningsHandler WarningHandler(S);
2808 if (
CFG *cfg = AC.getCFG()) {
2809 UninitValsDiagReporter reporter(S);
2816 ++NumUninitAnalysisFunctions;
2819 MaxUninitAnalysisVariablesPerFunction =
2820 std::max(MaxUninitAnalysisVariablesPerFunction,
2822 MaxUninitAnalysisBlockVisitsPerFunction =
2823 std::max(MaxUninitAnalysisBlockVisitsPerFunction,
2831 shouldAnalyzeCalledOnceParameters(Diags,
D->
getBeginLoc())) {
2833 CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);
2836 shouldAnalyzeCalledOnceConventions(Diags,
D->
getBeginLoc()));
2840 bool FallThroughDiagFull =
2842 bool FallThroughDiagPerFunction = !Diags.
isIgnored(
2843 diag::warn_unannotated_fallthrough_per_function,
D->
getBeginLoc());
2844 if (FallThroughDiagFull || FallThroughDiagPerFunction ||
2855 if (!Diags.
isIgnored(diag::warn_infinite_recursive_function,
2870 if (LogicalErrorHandler::hasActiveDiagnostics(Diags,
D->
getBeginLoc())) {
2876 ++NumFunctionsAnalyzed;
2877 if (
CFG *cfg = AC.getCFG()) {
2880 NumCFGBlocks += cfg->getNumBlockIDs();
2881 MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
2882 cfg->getNumBlockIDs());
2884 ++NumFunctionsWithBadCFGs;
2890 llvm::errs() <<
"\n*** Analysis Based Warnings Stats:\n";
2892 unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
2893 unsigned AvgCFGBlocksPerFunction =
2894 !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
2895 llvm::errs() << NumFunctionsAnalyzed <<
" functions analyzed ("
2896 << NumFunctionsWithBadCFGs <<
" w/o CFGs).\n"
2897 <<
" " << NumCFGBlocks <<
" CFG blocks built.\n"
2898 <<
" " << AvgCFGBlocksPerFunction
2899 <<
" average CFG blocks per function.\n"
2900 <<
" " << MaxCFGBlocksPerFunction
2901 <<
" max CFG blocks per function.\n";
2903 unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
2904 : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
2905 unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
2906 : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
2907 llvm::errs() << NumUninitAnalysisFunctions
2908 <<
" functions analyzed for uninitialiazed variables\n"
2909 <<
" " << NumUninitAnalysisVariables <<
" variables analyzed.\n"
2910 <<
" " << AvgUninitVariablesPerFunction
2911 <<
" average variables per function.\n"
2912 <<
" " << MaxUninitAnalysisVariablesPerFunction
2913 <<
" max variables per function.\n"
2914 <<
" " << NumUninitAnalysisBlockVisits <<
" block visits.\n"
2915 <<
" " << AvgUninitBlockVisitsPerFunction
2916 <<
" average block visits per function.\n"
2917 <<
" " << MaxUninitAnalysisBlockVisitsPerFunction
2918 <<
" max block visits per function.\n";
static void visitReachableThrows(CFG *BodyCFG, llvm::function_ref< void(const CXXThrowExpr *, CFGBlock &)> Visit)
static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD)
static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM, const Stmt *S)
static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC)
CheckFallThrough - Check that we don't fall off the end of a Statement that should return a value.
static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope)
static void diagnoseRepeatedUseOfWeak(Sema &S, const sema::FunctionScopeInfo *CurFn, const Decl *D, const ParentMap &PM)
static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, const FunctionDecl *FD)
static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, bool PerFunction)
static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, AnalysisDeclContext &AC)
static void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then, const Stmt *Else, bool CondVal, FixItHint &Fixit1, FixItHint &Fixit2)
Create a fixit to remove an if-like statement, on the assumption that its condition is CondVal.
static StringRef getFallthroughAttrSpelling(Preprocessor &PP, SourceLocation Loc)
static unsigned isEnabled(DiagnosticsEngine &D, unsigned diag)
static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, const UninitUse &Use, bool alwaysReportSelfInit=false)
DiagnoseUninitializedUse – Helper function for diagnosing uses of an uninitialized variable.
static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block)
static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock, CFG *Body)
Determine whether an exception thrown by E, unwinding from ThrowBlock, can reach ExitBlock.
static bool isNoexcept(const FunctionDecl *FD)
static bool DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD, const UninitUse &Use)
Diagnose uninitialized const reference usages.
static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, bool IsCapturedByBlock)
DiagUninitUse – Helper function to produce a diagnostic for an uninitialized use of a variable.
static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC)
CheckUnreachable - Check for unreachable code.
static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, QualType BlockType, const CheckFallThroughDiagnostics &CD, AnalysisDeclContext &AC, sema::FunctionScopeInfo *FSI)
CheckFallThroughForBody - Check that we don't fall off the end of a function that should return a val...
@ NeverFallThroughOrReturn
static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, const Stmt *Body, AnalysisDeclContext &AC)
static bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg)
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
Defines the Diagnostic-related interfaces.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
static bool EvaluateAsInt(const Expr *E, Expr::EvalResult &ExprResult, const ASTContext &Ctx, Expr::SideEffectsKind AllowSideEffects, EvalInfo &Info)
static std::pair< const Stmt *, const CFGBlock * > getLastStmt(const ExplodedNode *Node)
llvm::DenseSet< const void * > Visited
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
static void emitDiagnostics(BoundNodes &Match, const Decl *D, BugReporter &BR, AnalysisManager &AM, const ObjCAutoreleaseWriteChecker *Checker)
Defines the clang::Preprocessor interface.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Defines the Objective-C statement AST node classes.
C Language Family Type Representation.
@ Open
The standard open() call: int open(const char *path, int oflag, ...);.
TextDiagnosticBuffer::DiagList DiagList
__device__ __2f16 float __ockl_bool s
CallableVisitor(llvm::function_ref< void(const Decl *)> Callback)
bool VisitObjCMethodDecl(ObjCMethodDecl *Node) override
bool VisitBlockDecl(BlockDecl *Node) override
bool VisitFunctionDecl(FunctionDecl *Node) override
bool VisitLambdaExpr(LambdaExpr *Node) override
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
AnalysisDeclContext contains the context data for the function, method or block under analysis.
Represents an attribute applied to a statement.
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isLogicalOp(Opcode Opc)
SourceLocation getBeginLoc() const LLVM_READONLY
SourceLocation getOperatorLoc() const
SourceLocation getExprLoc() const
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
Represents a block literal declaration, which is like an unnamed FunctionDecl.
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
SourceLocation getBeginLoc() const LLVM_READONLY
unsigned IgnoreDefaultsWithCoveredEnums
Represents a single basic block in a source-level CFG.
filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const
reverse_iterator rbegin()
bool hasNoReturnElement() const
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
pred_iterator pred_begin()
unsigned getBlockID() const
unsigned succ_size() const
CFGCallback defines methods that should be called when a logical operator error is found when buildin...
virtual void compareBitwiseEquality(const BinaryOperator *B, bool isAlwaysTrue)
virtual void logicAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue)
virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue)
virtual void compareBitwiseOr(const BinaryOperator *B)
Represents a top-level expression in a basic block.
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type.
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
bool isReachable(const CFGBlock *Src, const CFGBlock *Dst)
Returns true if the block 'Dst' can be reached from block 'Src'.
const Stmt * getStmt() const
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Represents a call to a member function that may be written either with member call syntax (e....
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
Represents a static or instance method of a struct/union/class.
A C++ throw-expression (C++ [except.throw]).
SourceLocation getThrowLoc() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
virtual void handleBlockThatIsGuaranteedToBeCalledOnce(const BlockDecl *Block)
Called when the block is guaranteed to be called exactly once.
virtual void handleBlockWithNoGuarantees(const BlockDecl *Block)
Called when the block has no guarantees about how many times it can get called.
virtual void handleDoubleCall(const ParmVarDecl *Parameter, const Expr *Call, const Expr *PrevCall, bool IsCompletionHandler, bool Poised)
Called when parameter is called twice.
virtual void handleNeverCalled(const ParmVarDecl *Parameter, bool IsCompletionHandler)
Called when parameter is not called at all.
virtual void handleCapturedNeverCalled(const ParmVarDecl *Parameter, const Decl *Where, bool IsCompletionHandler)
Called when captured parameter is not called at all.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getBegin() const
ConditionalOperator - The ?: ternary operator.
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
Expr * getCond() const
getCond - Return the expression representing the condition for the ?: operator.
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
ConstEvaluatedExprVisitor - This class visits 'const Expr *'s.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
SourceLocation getEndLoc() const LLVM_READONLY
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
SourceLocation getLocation() const
SourceLocation getBeginLoc() const LLVM_READONLY
DeclContext * getLexicalDeclContext()
getLexicalDeclContext - The declaration context where this Decl was lexically declared (LexicalDC).
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
OverloadedOperatorKind getCXXOverloadedOperator() const
If this name is the name of an overloadable operator in C++ (e.g., operator+), retrieve the kind of o...
SourceLocation getBeginLoc() const LLVM_READONLY
TypeSourceInfo * getTypeSourceInfo() const
Options for controlling the compiler diagnostics engine.
Concrete class used by the front-end to report problems and issues.
bool getIgnoreAllWarnings() const
DiagnosticOptions & getDiagnosticOptions() const
Retrieve the diagnostic options.
bool isIgnored(unsigned DiagID, SourceLocation Loc) const
Determine whether the diagnostic is known to be ignored.
bool getSuppressSystemWarnings() const
Recursive AST visitor that supports extension via dynamic dispatch.
virtual bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
virtual bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, Expr *Init)
Recursively visit a lambda capture.
void VisitDeclRefExpr(PTR(DeclRefExpr) E)
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
static FixItHint CreateRemoval(CharSourceRange RemoveRange)
Create a code modification hint that removes the given source range.
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
Kind lookup(const VarDecl *VD) const
Represents a function declaration or definition.
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
FunctionDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
SourceRange getExceptionSpecSourceRange() const
Attempt to compute an informative source range covering the function exception specification,...
@ TK_MemberSpecialization
TemplatedKind getTemplatedKind() const
What kind of templated function this is.
bool isCPUDispatchMultiVersion() const
True if this function is a multiversioned dispatch function as a part of the cpu_specific/cpu_dispatc...
Represents a prototype with parameter type info, e.g.
FunctionType - C99 6.7.5.3 - Function Declarators.
IfStmt - This represents an if/then/else.
LabelStmt - Represents a label, which has a substatement.
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
This represents a decl that may have a name.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
@ TypeSpec
A type, stored as a Type*.
ObjCMethodDecl - Represents an instance or class method declaration.
Represents one property declaration in an Objective-C interface.
Stmt * getParent(Stmt *) const
Represents a parameter to a function.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
bool isSafeBufferOptOut(const SourceManager &SourceMgr, const SourceLocation &Loc) const
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
const LangOptions & getLangOpts() const
StringRef getLastMacroWithSpelling(SourceLocation Loc, ArrayRef< TokenValue > Tokens) const
Return the name of the macro defined before Loc that has spelling Tokens.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
QualType getCanonicalType() const
bool hasObjCLifetime() const
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
PartialDiagnostic PDiag(unsigned DiagID=0)
Build a partial diagnostic.
Sema - This implements semantic analysis and AST building for C.
Preprocessor & getPreprocessor() const
DiagnosticsEngine & getDiagnostics() const
ASTContext & getASTContext() const
std::string getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const
Get a string to suggest for zero-initialization of a type.
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Calls Lexer::getLocForEndOfToken()
const LangOptions & getLangOpts() const
threadSafety::BeforeSet * ThreadSafetyDeclCache
bool CollectStats
Flag indicating whether or not to collect detailed statistics.
SourceManager & getSourceManager() const
bool handlerCanCatch(QualType HandlerType, QualType ExceptionType)
bool hasUncompilableErrorOccurred() const
Whether uncompilable error has occurred.
SourceManager & SourceMgr
DiagnosticsEngine & Diags
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
bool isInMainFile(SourceLocation Loc) const
Returns whether the PresumedLoc for a given SourceLocation is in the main file.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
Stmt - This represents one statement.
SourceLocation getEndLoc() const LLVM_READONLY
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SourceLocation getBeginLoc() const LLVM_READONLY
SwitchStmt - This represents a 'switch' stmt.
Stores token information for comparing actual tokens with predefined values.
The top declaration context.
QualType getType() const
Return the type wrapped by this type source info.
bool isBlockPointerType() const
bool isPointerType() const
const T * castAs() const
Member-template castAs<specific type>.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const T * getAs() const
Member-template getAs<specific type>'.
TagDecl * getAsTagDecl() const
Retrieves the TagDecl that this type refers to, either because the type is a TagType or because it is...
A use of a variable, which might be uninitialized.
const Expr * getUser() const
Get the expression containing the uninitialized use.
SmallVectorImpl< Branch >::const_iterator branch_iterator
branch_iterator branch_end() const
branch_iterator branch_begin() const
Branches which inevitably result in the variable being used uninitialized.
@ Always
The use is always uninitialized.
@ AfterDecl
The use is uninitialized the first time it is reached after we reach the variable's declaration.
@ Maybe
The use might be uninitialized.
@ AfterCall
The use is uninitialized the first time it is reached after the function is called.
@ Sometimes
The use is uninitialized whenever a certain branch is taken.
Kind getKind() const
Get the kind of uninitialized use.
virtual void handleUseOfUninitVariable(const VarDecl *vd, const UninitUse &use)
Called when the uninitialized variable is used at the given expression.
virtual void handleSelfInit(const VarDecl *vd)
Called when the uninitialized variable analysis detects the idiom 'int x = x'.
virtual void handleConstRefUseOfUninitVariable(const VarDecl *vd, const UninitUse &use)
Called when the uninitialized variable is used as const refernce argument.
The interface that lets the caller handle unsafe buffer usage analysis results by overriding this cla...
bool areDebugNotesRequested()
virtual std::string getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, StringRef WSSuffix="") const =0
virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const =0
virtual bool ignoreUnsafeBufferInContainer(const SourceLocation &Loc) const =0
virtual void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation over raw pointers is found.
virtual void handleUnsafeVariableGroup(const VarDecl *Variable, const VariableGroupsManager &VarGrpMgr, FixItList &&Fixes, const Decl *D, const FixitStrategy &VarTargetTypes)=0
Invoked when a fix is suggested against a variable.
virtual void handleUnsafeOperationInContainer(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation with a std container is found.
virtual bool ignoreUnsafeBufferInLibcCall(const SourceLocation &Loc) const =0
virtual void handleUnsafeLibcCall(const CallExpr *Call, unsigned PrintfInfo, ASTContext &Ctx, const Expr *UnsafeArg=nullptr)=0
Invoked when a call to an unsafe libc function is found.
Represents a variable declaration or definition.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
const Expr * getInit() const
virtual VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm=nullptr) const =0
Returns the set of variables (including Var) that need to be fixed together in one step.
A class that handles the analysis of uniqueness violations.
void run(AnalysisDeclContext &AC)
Check a function's CFG for consumed violations.
virtual void HandleUnreachable(UnreachableKind UK, SourceLocation L, SourceRange ConditionVal, SourceRange R1, SourceRange R2, bool HasFallThroughAttr)=0
void IssueWarnings(Policy P, FunctionScopeInfo *fscope, const Decl *D, QualType BlockType)
AnalysisBasedWarnings(Sema &s)
Represents a simple identification of a weak object.
Retains information about a function, method, or block that is currently being parsed.
llvm::SmallDenseMap< WeakObjectProfileTy, WeakUseVector, 8, WeakObjectProfileTy::DenseMapInfo > WeakObjectUseMap
Used to collect all uses of weak objects in a function body.
bool HasFallthroughStmt
Whether there is a fallthrough statement in this function.
VarDecl * CoroutinePromise
The promise object for this coroutine, if any.
SmallVector< PossiblyUnreachableDiag, 4 > PossiblyUnreachableDiags
A list of PartialDiagnostics created but delayed within the current function scope.
const WeakObjectUseMap & getWeakObjectUses() const
Handler class for thread safety warnings.
InterProceduralData aims to be a storage of whatever data should be passed between analyses of differ...
CalledOnceInterProceduralData CalledOnceData
SmallVector< PartialDiagnosticAt, 1 > OptionalNotes
std::pair< PartialDiagnosticAt, OptionalNotes > DelayedDiag
bool LE(InterpState &S, CodePtr OpPC)
void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP, Callback &CB)
unsigned ScanReachableFromBlock(const CFGBlock *Start, llvm::BitVector &Reachable)
ScanReachableFromBlock - Mark all blocks reachable from Start.
UnreachableKind
Classifications of unreachable code.
LockKind getLockKindFromAccessKind(AccessKind AK)
Helper function that returns a LockKind required for the given level of access.
@ LEK_NotLockedAtEndOfFunction
@ LEK_LockedSomePredecessors
@ LEK_LockedAtEndOfFunction
@ LEK_LockedSomeLoopIterations
LockKind
This enum distinguishes between different kinds of lock actions.
void runThreadSafetyAnalysis(AnalysisDeclContext &AC, ThreadSafetyHandler &Handler, BeforeSet **Bset)
Check a function's CFG for thread-safety violations.
ProtectedOperationKind
This enum distinguishes between different kinds of operations that may need to be protected by locks.
@ POK_PtPassByRef
Passing a pt-guarded variable by reference.
@ POK_VarDereference
Dereferencing a variable (e.g. p in *p = 5;)
@ POK_PassByRef
Passing a guarded variable by reference.
@ POK_ReturnByRef
Returning a guarded variable by reference.
@ POK_VarAccess
Reading or writing a variable (e.g. x in x = 5;)
@ POK_FunctionCall
Making a function call (e.g. fool())
@ POK_PtReturnByRef
Returning a pt-guarded variable by reference.
The JSON file list parser is used to communicate input to InstallAPI.
bool isTemplateInstantiation(TemplateSpecializationKind Kind)
Determine whether this template specialization kind refers to an instantiation of an entity (as oppos...
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
@ If
'if' clause, allowed on all the Compute Constructs, Data Constructs, Executable Constructs,...
@ Property
The type of a property.
@ Parameter
The parameter type of a method or function.
void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats)
void checkCalledOnceParameters(AnalysisDeclContext &AC, CalledOnceCheckHandler &Handler, bool CheckConventionalParameters)
Check given CFG for 'called once' parameter violations.
std::pair< SourceLocation, PartialDiagnostic > PartialDiagnosticAt
A partial diagnostic along with the source location where this diagnostic occurs.
EvalResult is a struct with detailed info about an evaluated expression.
unsigned NumVariablesAnalyzed