47#include "llvm/ADT/ArrayRef.h"
48#include "llvm/ADT/BitVector.h"
49#include "llvm/ADT/MapVector.h"
50#include "llvm/ADT/STLFunctionalExtras.h"
51#include "llvm/ADT/SmallString.h"
52#include "llvm/ADT/SmallVector.h"
53#include "llvm/ADT/StringRef.h"
54#include "llvm/Support/Casting.h"
72 UnreachableCodeHandler(
Sema &
s) : S(
s) {}
80 if (HasFallThroughAttr &&
87 if (PreviousSilenceableCondVal.
isValid() &&
89 PreviousSilenceableCondVal == SilenceableCondVal)
91 PreviousSilenceableCondVal = SilenceableCondVal;
93 unsigned diag = diag::warn_unreachable;
96 diag = diag::warn_unreachable_break;
99 diag = diag::warn_unreachable_return;
102 diag = diag::warn_unreachable_loop_increment;
108 S.
Diag(L, diag) << R1 << R2;
111 if (
Open.isValid()) {
115 S.
Diag(
Open, diag::note_unreachable_silence)
136 UnreachableCodeHandler UC(S);
146 LogicalErrorHandler(
Sema &S) : S(S) {}
148 static bool HasMacroID(
const Expr *
E) {
154 if (
const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt))
155 if (HasMacroID(SubExpr))
165 unsigned DiagID = isAlwaysTrue
166 ? diag::warn_tautological_negation_or_compare
167 : diag::warn_tautological_negation_and_compare;
177 S.
Diag(B->
getExprLoc(), diag::warn_tautological_overlap_comparison)
178 << DiagRange << isAlwaysTrue;
182 bool isAlwaysTrue)
override {
188 << DiagRange << isAlwaysTrue;
196 S.
Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;
201 return !Diags.
isIgnored(diag::warn_tautological_overlap_comparison,
Loc) ||
202 !Diags.
isIgnored(diag::warn_comparison_bitwise_or,
Loc) ||
203 !Diags.
isIgnored(diag::warn_tautological_negation_and_compare,
Loc);
217 for (
const auto &B :
Block) {
231 isa<TemplateSpecializationType>(NNS->getAsType())) {
250 bool foundRecursion =
false;
255 WorkList.push_back(&cfg->
getEntry());
257 while (!WorkList.empty()) {
262 if (!
Visited.insert(SuccBlock).second)
266 if (ExitID == SuccBlock->getBlockID())
271 foundRecursion =
true;
275 WorkList.push_back(SuccBlock);
279 return foundRecursion;
292 CFG *cfg = AC.getCFG();
315 Stack.push_back(&ThrowBlock);
318 while (!Stack.empty()) {
319 CFGBlock &UnwindBlock = *Stack.back();
322 for (
auto &Succ : UnwindBlock.
succs()) {
323 if (!Succ.isReachable() || Queued[Succ->getBlockID()])
330 dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
331 QualType Caught = Catch->getCaughtType();
338 Stack.push_back(Succ);
339 Queued[Succ->getBlockID()] =
true;
353 if (!Reachable[B->getBlockID()])
356 std::optional<CFGStmt> S =
E.getAs<
CFGStmt>();
359 if (
auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))
369 S.
Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
371 (isa<CXXDestructorDecl>(FD) ||
375 getAs<FunctionProtoType>())
377 << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec()
387 CFG *BodyCFG = AC.getCFG();
400 if (FPT->isNothrow() || FD->
hasAttr<NoThrowAttr>())
427 CFG *cfg = AC.getCFG();
436 bool AddEHEdges = AC.getAddEHEdges();
441 for (
const auto *B : *cfg) {
442 if (!live[B->getBlockID()]) {
443 if (B->pred_begin() == B->pred_end()) {
444 const Stmt *Term = B->getTerminatorStmt();
445 if (isa_and_nonnull<CXXTryStmt>(Term))
457 bool HasLiveReturn =
false;
458 bool HasFakeEdge =
false;
459 bool HasPlainEdge =
false;
460 bool HasAbnormalEdge =
false;
478 HasAbnormalEdge =
true;
487 for ( ; ri != re ; ++ri)
494 if (Term && (isa<CXXTryStmt>(Term) || isa<ObjCAtTryStmt>(Term))) {
495 HasAbnormalEdge =
true;
505 if (isa<ReturnStmt>(S) || isa<CoreturnStmt>(S)) {
506 HasLiveReturn =
true;
509 if (isa<ObjCAtThrowStmt>(S)) {
513 if (isa<CXXThrowExpr>(S)) {
517 if (isa<MSAsmStmt>(S)) {
520 HasLiveReturn =
true;
523 if (isa<CXXTryStmt>(S)) {
524 HasAbnormalEdge =
true;
528 HasAbnormalEdge =
true;
539 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
549struct CheckFallThroughDiagnostics {
550 unsigned diag_MaybeFallThrough_HasNoReturn;
551 unsigned diag_MaybeFallThrough_ReturnsNonVoid;
552 unsigned diag_AlwaysFallThrough_HasNoReturn;
553 unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
554 unsigned diag_NeverFallThroughOrReturn;
558 static CheckFallThroughDiagnostics MakeForFunction(
const Decl *
Func) {
559 CheckFallThroughDiagnostics
D;
560 D.FuncLoc =
Func->getLocation();
561 D.diag_MaybeFallThrough_HasNoReturn =
562 diag::warn_falloff_noreturn_function;
563 D.diag_MaybeFallThrough_ReturnsNonVoid =
564 diag::warn_maybe_falloff_nonvoid_function;
565 D.diag_AlwaysFallThrough_HasNoReturn =
566 diag::warn_falloff_noreturn_function;
567 D.diag_AlwaysFallThrough_ReturnsNonVoid =
568 diag::warn_falloff_nonvoid_function;
572 bool isVirtualMethod =
false;
574 isVirtualMethod = Method->isVirtual();
582 D.diag_NeverFallThroughOrReturn =
583 diag::warn_suggest_noreturn_function;
585 D.diag_NeverFallThroughOrReturn = 0;
591 static CheckFallThroughDiagnostics MakeForCoroutine(
const Decl *
Func) {
592 CheckFallThroughDiagnostics
D;
593 D.FuncLoc =
Func->getLocation();
594 D.diag_MaybeFallThrough_HasNoReturn = 0;
595 D.diag_MaybeFallThrough_ReturnsNonVoid =
596 diag::warn_maybe_falloff_nonvoid_coroutine;
597 D.diag_AlwaysFallThrough_HasNoReturn = 0;
598 D.diag_AlwaysFallThrough_ReturnsNonVoid =
599 diag::warn_falloff_nonvoid_coroutine;
600 D.diag_NeverFallThroughOrReturn = 0;
601 D.funMode = Coroutine;
605 static CheckFallThroughDiagnostics MakeForBlock() {
606 CheckFallThroughDiagnostics
D;
607 D.diag_MaybeFallThrough_HasNoReturn =
608 diag::err_noreturn_block_has_return_expr;
609 D.diag_MaybeFallThrough_ReturnsNonVoid =
610 diag::err_maybe_falloff_nonvoid_block;
611 D.diag_AlwaysFallThrough_HasNoReturn =
612 diag::err_noreturn_block_has_return_expr;
613 D.diag_AlwaysFallThrough_ReturnsNonVoid =
614 diag::err_falloff_nonvoid_block;
615 D.diag_NeverFallThroughOrReturn = 0;
620 static CheckFallThroughDiagnostics MakeForLambda() {
621 CheckFallThroughDiagnostics
D;
622 D.diag_MaybeFallThrough_HasNoReturn =
623 diag::err_noreturn_lambda_has_return_expr;
624 D.diag_MaybeFallThrough_ReturnsNonVoid =
625 diag::warn_maybe_falloff_nonvoid_lambda;
626 D.diag_AlwaysFallThrough_HasNoReturn =
627 diag::err_noreturn_lambda_has_return_expr;
628 D.diag_AlwaysFallThrough_ReturnsNonVoid =
629 diag::warn_falloff_nonvoid_lambda;
630 D.diag_NeverFallThroughOrReturn = 0;
636 bool HasNoReturn)
const {
637 if (funMode == Function) {
638 return (ReturnsVoid ||
639 D.isIgnored(diag::warn_maybe_falloff_nonvoid_function,
642 D.isIgnored(diag::warn_noreturn_function_has_return_expr,
645 D.isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));
647 if (funMode == Coroutine) {
648 return (ReturnsVoid ||
649 D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, FuncLoc) ||
650 D.isIgnored(diag::warn_maybe_falloff_nonvoid_coroutine,
655 return ReturnsVoid && !HasNoReturn;
667 const CheckFallThroughDiagnostics &CD,
671 bool ReturnsVoid =
false;
672 bool HasNoReturn =
false;
675 if (
const auto *FD = dyn_cast<FunctionDecl>(
D)) {
676 if (
const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
677 ReturnsVoid = CBody->getFallthroughHandler() !=
nullptr;
679 ReturnsVoid = FD->getReturnType()->isVoidType();
680 HasNoReturn = FD->isNoReturn();
682 else if (
const auto *MD = dyn_cast<ObjCMethodDecl>(
D)) {
683 ReturnsVoid = MD->getReturnType()->isVoidType();
684 HasNoReturn = MD->hasAttr<NoReturnAttr>();
686 else if (isa<BlockDecl>(
D)) {
689 if (FT->getReturnType()->isVoidType())
691 if (FT->getNoReturnAttr())
699 if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
720 EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);
721 else if (!ReturnsVoid)
722 EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);
726 EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);
727 else if (!ReturnsVoid)
728 EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
731 if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
733 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
735 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
737 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
762 : Inherited(Context), FoundReference(
false), Needle(Needle) {}
764 void VisitExpr(
const Expr *
E) {
769 Inherited::VisitExpr(
E);
774 FoundReference =
true;
779 bool doesContainReference()
const {
return FoundReference; }
787 S.
Diag(VD->
getLocation(), diag::note_block_var_fixit_add_initialization)
816 const Stmt *Else,
bool CondVal,
840 bool IsCapturedByBlock) {
841 bool Diagnosed =
false;
874 const Stmt *Term = I->Terminator;
884 int RemoveDiagKind = -1;
885 const char *FixitStr =
886 S.
getLangOpts().CPlusPlus ? (I->Output ?
"true" :
"false")
887 : (I->Output ?
"1" :
"0");
890 switch (Term ? Term->
getStmtClass() : Stmt::DeclStmtClass) {
897 case Stmt::IfStmtClass: {
898 const IfStmt *IS = cast<IfStmt>(Term);
904 I->Output, Fixit1, Fixit2);
907 case Stmt::ConditionalOperatorClass: {
914 I->Output, Fixit1, Fixit2);
917 case Stmt::BinaryOperatorClass: {
925 if ((BO->
getOpcode() == BO_LAnd && I->Output) ||
926 (BO->
getOpcode() == BO_LOr && !I->Output))
937 case Stmt::WhileStmtClass:
940 Range = cast<WhileStmt>(Term)->getCond()->getSourceRange();
944 case Stmt::ForStmtClass:
947 Range = cast<ForStmt>(Term)->getCond()->getSourceRange();
954 case Stmt::CXXForRangeStmtClass:
955 if (I->Output == 1) {
963 Range = cast<CXXForRangeStmt>(Term)->getRangeInit()->getSourceRange();
967 case Stmt::DoStmtClass:
970 Range = cast<DoStmt>(Term)->getCond()->getSourceRange();
976 case Stmt::CaseStmtClass:
979 Range = cast<CaseStmt>(Term)->getLHS()->getSourceRange();
981 case Stmt::DefaultStmtClass:
984 Range = cast<DefaultStmt>(Term)->getDefaultLoc();
989 << VD->
getDeclName() << IsCapturedByBlock << DiagKind
990 << Str << I->Output <<
Range;
993 if (RemoveDiagKind != -1)
995 << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
1021 bool alwaysReportSelfInit =
false) {
1035 if (!alwaysReportSelfInit && DRE ==
Initializer->IgnoreParenImpCasts())
1038 ContainsReference CR(S.
Context, DRE);
1040 if (CR.doesContainReference()) {
1041 S.
Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
1052 diag::warn_uninit_byref_blockvar_captured_by_block)
1072 FallthroughMapper(
Sema &S)
1073 : FoundSwitchStatements(
false),
1077 bool foundSwitchStatements()
const {
return FoundSwitchStatements; }
1080 bool Found = FallthroughStmts.erase(
Stmt);
1087 const AttrStmts &getFallthroughStmts()
const {
1088 return FallthroughStmts;
1091 void fillReachableBlocks(
CFG *Cfg) {
1092 assert(ReachableBlocks.empty() &&
"ReachableBlocks already filled");
1093 std::deque<const CFGBlock *> BlockQueue;
1095 ReachableBlocks.insert(&Cfg->
getEntry());
1096 BlockQueue.push_back(&Cfg->
getEntry());
1101 for (
const auto *B : *Cfg) {
1102 const Stmt *L = B->getLabel();
1103 if (isa_and_nonnull<SwitchCase>(L) && ReachableBlocks.insert(B).second)
1104 BlockQueue.push_back(B);
1107 while (!BlockQueue.empty()) {
1109 BlockQueue.pop_front();
1111 if (B && ReachableBlocks.insert(B).second)
1112 BlockQueue.push_back(B);
1117 bool checkFallThroughIntoBlock(
const CFGBlock &B,
int &AnnotatedCnt,
1118 bool IsTemplateInstantiation) {
1119 assert(!ReachableBlocks.empty() &&
"ReachableBlocks empty");
1121 int UnannotatedCnt = 0;
1125 while (!BlockQueue.empty()) {
1127 BlockQueue.pop_front();
1130 const Stmt *Term =
P->getTerminatorStmt();
1131 if (isa_and_nonnull<SwitchStmt>(Term))
1134 const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(
P->getLabel());
1138 const LabelStmt *L = dyn_cast_or_null<LabelStmt>(
P->getLabel());
1142 if (!ReachableBlocks.count(
P)) {
1143 for (
const CFGElement &Elem : llvm::reverse(*
P)) {
1144 if (std::optional<CFGStmt> CS = Elem.getAs<
CFGStmt>()) {
1145 if (
const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
1149 if (!IsTemplateInstantiation)
1150 S.
Diag(AS->getBeginLoc(),
1151 diag::warn_unreachable_fallthrough_attr);
1152 markFallthroughVisited(AS);
1172 markFallthroughVisited(AS);
1179 std::copy(
P->pred_begin(),
P->pred_end(),
1180 std::back_inserter(BlockQueue));
1186 return !!UnannotatedCnt;
1193 if (asFallThroughAttr(S))
1194 FallthroughStmts.insert(S);
1199 FoundSwitchStatements =
true;
1210 for (
const auto C : zip(
LE->captures(),
LE->capture_inits()))
1218 if (
const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
1219 if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs()))
1228 for (
const CFGElement &Elem : llvm::reverse(B))
1229 if (std::optional<CFGStmt> CS = Elem.getAs<
CFGStmt>())
1230 return CS->getStmt();
1241 bool FoundSwitchStatements;
1242 AttrStmts FallthroughStmts;
1251 tok::l_square, tok::l_square,
1253 tok::r_square, tok::r_square
1259 tok::r_square, tok::r_square
1264 StringRef MacroName;
1265 if (PreferClangAttr)
1267 if (MacroName.empty())
1269 if (MacroName.empty() && !PreferClangAttr)
1271 if (MacroName.empty()) {
1272 if (!PreferClangAttr)
1273 MacroName =
"[[fallthrough]]";
1275 MacroName =
"[[clang::fallthrough]]";
1277 MacroName =
"__attribute__((fallthrough))";
1284 FallthroughMapper FM(S);
1285 FM.TraverseStmt(AC.getBody());
1287 if (!FM.foundSwitchStatements())
1290 if (PerFunction && FM.getFallthroughStmts().empty())
1293 CFG *Cfg = AC.getCFG();
1298 FM.fillReachableBlocks(Cfg);
1300 for (
const CFGBlock *B : llvm::reverse(*Cfg)) {
1303 if (!isa_and_nonnull<SwitchCase>(
Label))
1308 bool IsTemplateInstantiation =
false;
1310 IsTemplateInstantiation =
Function->isTemplateInstantiation();
1311 if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,
1312 IsTemplateInstantiation))
1316 PerFunction ? diag::warn_unannotated_fallthrough_per_function
1317 : diag::warn_unannotated_fallthrough);
1319 if (!AnnotatedCnt) {
1330 if (!(B->
empty() && isa_and_nonnull<BreakStmt>(Term))) {
1334 TextToInsert +=
"; ";
1335 S.
Diag(L, diag::note_insert_fallthrough_fixit)
1336 << AnnotationSpelling
1339 S.
Diag(L, diag::note_insert_break_fixit)
1344 for (
const auto *F : FM.getFallthroughStmts())
1345 S.
Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement);
1353 switch (S->getStmtClass()) {
1354 case Stmt::ForStmtClass:
1355 case Stmt::WhileStmtClass:
1356 case Stmt::CXXForRangeStmtClass:
1357 case Stmt::ObjCForCollectionStmtClass:
1359 case Stmt::DoStmtClass: {
1361 if (!cast<DoStmt>(S)->getCond()->
EvaluateAsInt(Result, Ctx))
1363 return Result.Val.getInt().getBoolValue();
1380 typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
1389 for (WeakObjectUseMap::const_iterator I = WeakMap.begin(),
E = WeakMap.end();
1391 const WeakUseVector &Uses = I->second;
1394 WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
1395 for ( ; UI != UE; ++UI) {
1408 if (UI == Uses.begin()) {
1409 WeakUseVector::const_iterator UI2 = UI;
1410 for (++UI2; UI2 != UE; ++UI2)
1411 if (UI2->isUnsafe())
1415 if (!
isInLoop(Ctx, PM, UI->getUseExpr()))
1418 const WeakObjectProfileTy &Profile = I->first;
1419 if (!Profile.isExactProfile())
1424 Base = Profile.getProperty();
1425 assert(
Base &&
"A profile always has a base or property.");
1427 if (
const VarDecl *BaseVar = dyn_cast<VarDecl>(
Base))
1428 if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(
Base))
1433 UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
1436 if (UsesByStmt.empty())
1441 llvm::sort(UsesByStmt,
1442 [&
SM](
const StmtUsesPair &LHS,
const StmtUsesPair &RHS) {
1444 RHS.first->getBeginLoc());
1459 if (isa<sema::BlockScopeInfo>(CurFn))
1460 FunctionKind =
Block;
1461 else if (isa<sema::LambdaScopeInfo>(CurFn))
1462 FunctionKind = Lambda;
1463 else if (isa<ObjCMethodDecl>(
D))
1464 FunctionKind = Method;
1469 for (
const auto &
P : UsesByStmt) {
1470 const Stmt *FirstRead =
P.first;
1471 const WeakObjectProfileTy &Key =
P.second->first;
1472 const WeakUseVector &Uses =
P.second->second;
1480 if (Key.isExactProfile())
1481 DiagKind = diag::warn_arc_repeated_use_of_weak;
1483 DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
1495 const NamedDecl *KeyProp = Key.getProperty();
1496 if (isa<VarDecl>(KeyProp))
1498 else if (isa<ObjCPropertyDecl>(KeyProp))
1500 else if (isa<ObjCMethodDecl>(KeyProp))
1501 ObjectKind = ImplicitProperty;
1502 else if (isa<ObjCIvarDecl>(KeyProp))
1505 llvm_unreachable(
"Unexpected weak object kind!");
1510 if (Prop->hasAttr<IBOutletAttr>())
1515 <<
int(ObjectKind) << KeyProp <<
int(FunctionKind)
1519 for (
const auto &Use : Uses) {
1520 if (Use.getUseExpr() == FirstRead)
1522 S.
Diag(Use.getUseExpr()->getBeginLoc(),
1523 diag::note_arc_weak_also_accessed_here)
1524 << Use.getUseExpr()->getSourceRange();
1532typedef std::pair<PartialDiagnosticAt, OptionalNotes>
DelayedDiag;
1533typedef std::list<DelayedDiag>
DiagList;
1535struct SortDiagBySourceLocation {
1539 bool operator()(
const DelayedDiag &left,
const DelayedDiag &right) {
1542 return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
1552 typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
1556 typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
1558 UsesMap constRefUses;
1561 UninitValsDiagReporter(
Sema &S) : S(S) {}
1564 MappedType &getUses(UsesMap &um,
const VarDecl *vd) {
1565 MappedType &
V = um[vd];
1566 if (!
V.getPointer())
1567 V.setPointer(
new UsesVec());
1573 getUses(uses, vd).getPointer()->push_back(use);
1578 getUses(constRefUses, vd).getPointer()->push_back(use);
1582 getUses(uses, vd).setInt(
true);
1583 getUses(constRefUses, vd).setInt(
true);
1587 for (
const auto &
P : uses) {
1589 const MappedType &
V =
P.second;
1591 UsesVec *vec =
V.getPointer();
1592 bool hasSelfInit =
V.getInt();
1597 if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
1613 for (
const auto &
U : *vec) {
1631 for (
const auto &
P : constRefUses) {
1633 const MappedType &
V =
P.second;
1635 UsesVec *vec =
V.getPointer();
1636 bool hasSelfInit =
V.getInt();
1638 if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
1644 for (
const auto &
U : *vec) {
1654 constRefUses.clear();
1658 static bool hasAlwaysUninitializedUse(
const UsesVec* vec) {
1659 return llvm::any_of(*vec, [](
const UninitUse &
U) {
1668class CalledOnceInterProceduralData {
1673 DelayedBlockWarnings[
Block].emplace_back(std::move(
Warning));
1678 S.
Diag(Delayed.first, Delayed.second);
1680 discardWarnings(
Block);
1684 DelayedBlockWarnings.erase(
Block);
1689 llvm::DenseMap<const BlockDecl *, DelayedDiagnostics> DelayedBlockWarnings;
1694 CalledOnceCheckReporter(
Sema &S, CalledOnceInterProceduralData &Data)
1697 const Expr *PrevCall,
bool IsCompletionHandler,
1698 bool Poised)
override {
1699 auto DiagToReport = IsCompletionHandler
1700 ? diag::warn_completion_handler_called_twice
1701 : diag::warn_called_once_gets_called_twice;
1703 S.
Diag(PrevCall->
getBeginLoc(), diag::note_called_once_gets_called_twice)
1708 bool IsCompletionHandler)
override {
1709 auto DiagToReport = IsCompletionHandler
1710 ? diag::warn_completion_handler_never_called
1711 : diag::warn_called_once_never_called;
1718 bool IsCalledDirectly,
1719 bool IsCompletionHandler)
override {
1720 auto DiagToReport = IsCompletionHandler
1721 ? diag::warn_completion_handler_never_called_when
1722 : diag::warn_called_once_never_called_when;
1726 << (
unsigned)Reason);
1728 if (
const auto *
Block = dyn_cast<BlockDecl>(Function)) {
1738 bool IsCompletionHandler)
override {
1739 auto DiagToReport = IsCompletionHandler
1740 ? diag::warn_completion_handler_never_called
1741 : diag::warn_called_once_never_called;
1757 CalledOnceInterProceduralData &
Data;
1760constexpr unsigned CalledOnceWarnings[] = {
1761 diag::warn_called_once_never_called,
1762 diag::warn_called_once_never_called_when,
1763 diag::warn_called_once_gets_called_twice};
1765constexpr unsigned CompletionHandlerWarnings[]{
1766 diag::warn_completion_handler_never_called,
1767 diag::warn_completion_handler_never_called_when,
1768 diag::warn_completion_handler_called_twice};
1773 return llvm::any_of(DiagIDs, [&Diags, At](
unsigned DiagID) {
1780 return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);
1785 return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||
1786 shouldAnalyzeCalledOnceConventions(Diags, At);
1794namespace threadSafety {
1805 if (Verbose && CurrentFunction) {
1807 S.
PDiag(diag::note_thread_warning_in_fun)
1808 << CurrentFunction);
1816 if (Verbose && CurrentFunction) {
1818 S.
PDiag(diag::note_thread_warning_in_fun)
1819 << CurrentFunction);
1820 ONS.push_back(std::move(FNote));
1828 ONS.push_back(Note1);
1829 ONS.push_back(Note2);
1830 if (Verbose && CurrentFunction) {
1832 S.
PDiag(diag::note_thread_warning_in_fun)
1833 << CurrentFunction);
1834 ONS.push_back(std::move(FNote));
1842 LocLocked, S.
PDiag(diag::note_locked_here) << Kind))
1850 LocUnlocked, S.
PDiag(diag::note_unlocked_here) << Kind))
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)
1877 Warnings.emplace_back(std::move(
Warning), getNotes());
1885 << Kind << LockName);
1886 Warnings.emplace_back(std::move(
Warning),
1887 makeUnlockedHereNote(LocPreviousUnlock, Kind));
1890 void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
1895 LocUnlock = FunLocation;
1897 LocUnlock, S.
PDiag(diag::warn_unlock_kind_mismatch)
1898 << Kind << LockName << Received <<
Expected);
1899 Warnings.emplace_back(std::move(
Warning),
1900 makeLockedHereNote(LocLocked, Kind));
1903 void handleDoubleLock(StringRef Kind, Name LockName,
SourceLocation LocLocked,
1906 LocDoubleLock = FunLocation;
1908 << Kind << LockName);
1909 Warnings.emplace_back(std::move(
Warning),
1910 makeLockedHereNote(LocLocked, Kind));
1913 void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
1917 unsigned DiagID = 0;
1920 DiagID = diag::warn_lock_some_predecessors;
1923 DiagID = diag::warn_expecting_lock_held_on_loop;
1926 DiagID = diag::warn_no_unlock;
1929 DiagID = diag::warn_expecting_locked;
1933 LocEndOfScope = FunEndLocation;
1937 Warnings.emplace_back(std::move(
Warning),
1938 makeLockedHereNote(LocLocked, Kind));
1941 void handleExclusiveAndShared(StringRef Kind, Name LockName,
1945 S.
PDiag(diag::warn_lock_exclusive_and_shared)
1946 << Kind << LockName);
1948 << Kind << LockName);
1949 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
1955 "Only works for variables");
1957 diag::warn_variable_requires_any_lock:
1958 diag::warn_var_deref_requires_any_lock;
1961 Warnings.emplace_back(std::move(
Warning), getNotes());
1964 void handleMutexNotHeld(StringRef Kind,
const NamedDecl *
D,
1967 Name *PossibleMatch)
override {
1968 unsigned DiagID = 0;
1969 if (PossibleMatch) {
1972 DiagID = diag::warn_variable_requires_lock_precise;
1975 DiagID = diag::warn_var_deref_requires_lock_precise;
1978 DiagID = diag::warn_fun_requires_lock_precise;
1981 DiagID = diag::warn_guarded_pass_by_reference;
1984 DiagID = diag::warn_pt_guarded_pass_by_reference;
1987 DiagID = diag::warn_guarded_return_by_reference;
1990 DiagID = diag::warn_pt_guarded_return_by_reference;
2000 S.
PDiag(diag::note_guarded_by_declared_here)
2001 <<
D->getDeclName());
2002 Warnings.emplace_back(std::move(
Warning), getNotes(
Note, VNote));
2004 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2008 DiagID = diag::warn_variable_requires_lock;
2011 DiagID = diag::warn_var_deref_requires_lock;
2014 DiagID = diag::warn_fun_requires_lock;
2017 DiagID = diag::warn_guarded_pass_by_reference;
2020 DiagID = diag::warn_pt_guarded_pass_by_reference;
2023 DiagID = diag::warn_guarded_return_by_reference;
2026 DiagID = diag::warn_pt_guarded_return_by_reference;
2034 S.
PDiag(diag::note_guarded_by_declared_here));
2035 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2037 Warnings.emplace_back(std::move(
Warning), getNotes());
2041 void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
2044 S.
PDiag(diag::warn_acquire_requires_negative_cap)
2045 << Kind << LockName << Neg);
2046 Warnings.emplace_back(std::move(
Warning), getNotes());
2049 void handleNegativeNotHeld(
const NamedDecl *
D, Name LockName,
2052 Loc, S.
PDiag(diag::warn_fun_requires_negative_cap) <<
D << LockName);
2053 Warnings.emplace_back(std::move(
Warning), getNotes());
2056 void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
2059 << Kind << FunName << LockName);
2060 Warnings.emplace_back(std::move(
Warning), getNotes());
2063 void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
2066 S.
PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
2067 Warnings.emplace_back(std::move(
Warning), getNotes());
2072 S.
PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
2073 Warnings.emplace_back(std::move(
Warning), getNotes());
2077 CurrentFunction = FD;
2081 CurrentFunction =
nullptr;
2095class ConsumedWarningsHandler :
public ConsumedWarningsHandlerBase {
2102 ConsumedWarningsHandler(
Sema &S) : S(S) {}
2106 for (
const auto &
Diag : Warnings) {
2108 for (
const auto &
Note :
Diag.second)
2114 StringRef VariableName)
override {
2122 StringRef VariableName,
2123 StringRef ExpectedState,
2124 StringRef ObservedState)
override {
2127 diag::warn_param_return_typestate_mismatch) << VariableName <<
2128 ExpectedState << ObservedState);
2134 StringRef ObservedState)
override {
2137 diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
2143 StringRef TypeName)
override {
2145 diag::warn_return_typestate_for_unconsumable_type) << TypeName);
2151 StringRef ObservedState)
override {
2154 diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
2159 void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
2163 diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
2168 void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
2172 MethodName << VariableName << State);
2188 bool SuggestSuggestions;
2192 std::string listVariableGroupAsString(
2194 if (VarGroupForVD.size() <= 1)
2197 std::vector<StringRef> VarNames;
2198 auto PutInQuotes = [](StringRef S) -> std::string {
2199 return "'" + S.str() +
"'";
2202 for (
auto *
V : VarGroupForVD) {
2205 VarNames.push_back(
V->getName());
2207 if (VarNames.size() == 1) {
2208 return PutInQuotes(VarNames[0]);
2210 if (VarNames.size() == 2) {
2211 return PutInQuotes(VarNames[0]) +
" and " + PutInQuotes(VarNames[1]);
2213 assert(VarGroupForVD.size() > 3);
2214 const unsigned N = VarNames.size() -
2216 std::string AllVars =
"";
2218 for (
unsigned I = 0; I < N; ++I)
2219 AllVars.append(PutInQuotes(VarNames[I]) +
", ");
2220 AllVars.append(PutInQuotes(VarNames[N]) +
", and " +
2221 PutInQuotes(VarNames[N + 1]));
2226 UnsafeBufferUsageReporter(
Sema &S,
bool SuggestSuggestions)
2227 : S(S), SuggestSuggestions(SuggestSuggestions) {}
2233 unsigned MsgParam = 0;
2235 if (
const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
2236 Loc = ASE->getBase()->getExprLoc();
2237 Range = ASE->getBase()->getSourceRange();
2239 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
2241 if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
2242 Op == BO_SubAssign) {
2243 if (BO->getRHS()->getType()->isIntegerType()) {
2244 Loc = BO->getLHS()->getExprLoc();
2245 Range = BO->getLHS()->getSourceRange();
2247 Loc = BO->getRHS()->getExprLoc();
2248 Range = BO->getRHS()->getSourceRange();
2252 }
else if (
const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
2254 if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
2256 Loc = UO->getSubExpr()->getExprLoc();
2257 Range = UO->getSubExpr()->getSourceRange();
2261 if (isa<CallExpr>(Operation) || isa<CXXConstructExpr>(Operation)) {
2263 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2265 }
else if (isa<MemberExpr>(Operation)) {
2267 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2268 auto ME = dyn_cast<MemberExpr>(Operation);
2269 D = ME->getMemberDecl();
2271 }
else if (
const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) {
2272 QualType destType = ECE->getType();
2273 if (!isa<PointerType>(destType))
2279 QualType srcType = ECE->getSubExpr()->getType();
2290 if (IsRelatedToDecl) {
2291 assert(!SuggestSuggestions &&
2292 "Variables blamed for unsafe buffer usage without suggestions!");
2293 S.
Diag(
Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2296 S.
Diag(
Loc, diag::warn_unsafe_buffer_operation)
2297 << MsgParam <<
D <<
Range;
2299 S.
Diag(
Loc, diag::warn_unsafe_buffer_operation) << MsgParam <<
Range;
2301 if (SuggestSuggestions) {
2302 S.
Diag(
Loc, diag::note_safe_buffer_usage_suggestions_disabled);
2308 bool IsRelatedToDecl,
2312 unsigned MsgParam = 0;
2316 const auto *CtorExpr = cast<CXXConstructExpr>(Operation);
2317 Loc = CtorExpr->getLocation();
2319 S.
Diag(
Loc, diag::warn_unsafe_buffer_usage_in_container);
2320 if (IsRelatedToDecl) {
2321 assert(!SuggestSuggestions &&
2322 "Variables blamed for unsafe buffer usage without suggestions!");
2323 S.
Diag(
Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2329 FixItList &&Fixes,
const Decl *
D,
2331 assert(!SuggestSuggestions &&
2332 "Unsafe buffer usage fixits displayed without suggestions!");
2336 if (!Fixes.empty()) {
2337 assert(isa<NamedDecl>(
D) &&
2338 "Fix-its are generated only for `NamedDecl`s");
2340 bool BriefMsg =
false;
2345 unsigned FixItStrategy = 0;
2354 assert(
false &&
"We support only std::span and std::array");
2359 BriefMsg ? diag::note_unsafe_buffer_variable_fixit_together
2360 : diag::note_unsafe_buffer_variable_fixit_group);
2363 FD << listVariableGroupAsString(
Variable, VarGroupForVD)
2364 << (VarGroupForVD.size() > 1) << ND;
2365 for (
const auto &F : Fixes) {
2373 S.
Diag(
Note.first, diag::note_safe_buffer_debug_mode) <<
Note.second;
2390 StringRef WSSuffix =
"")
const override {
2392 TokenValue ClangUnsafeBufferUsageTokens[] = {
2401 StringRef MacroName;
2405 if (MacroName.empty())
2406 MacroName =
"[[clang::unsafe_buffer_usage]]";
2407 return MacroName.str() + WSSuffix.str();
2418 enableCheckFallThrough = 1;
2419 enableCheckUnreachable = 0;
2420 enableThreadSafetyAnalysis = 0;
2421 enableConsumedAnalysis = 0;
2448 NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),
2449 MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),
2450 NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
2451 NumUninitAnalysisBlockVisits(0),
2452 MaxUninitAnalysisBlockVisitsPerFunction(0) {
2454 using namespace diag;
2457 DefaultPolicy.enableCheckUnreachable =
2460 isEnabled(
D, warn_unreachable_loop_increment);
2462 DefaultPolicy.enableThreadSafetyAnalysis =
isEnabled(
D, warn_double_lock);
2464 DefaultPolicy.enableConsumedAnalysis =
2480 llvm::function_ref<void(
const Decl *)> Callback;
2484 : Callback(Callback) {}
2487 if (cast<DeclContext>(
Node)->isDependentContext())
2492 if (
Node->doesThisDeclarationHaveABody())
2498 if (cast<DeclContext>(
Node)->isDependentContext())
2505 if (cast<DeclContext>(
Node)->isDependentContext())
2507 if (
Node->hasBody())
2513 return VisitFunctionDecl(
Node->getCallOperator());
2534 bool UnsafeBufferUsageCanEmitSuggestions = S.
getLangOpts().CPlusPlus20;
2535 bool UnsafeBufferUsageShouldEmitSuggestions =
2536 UnsafeBufferUsageCanEmitSuggestions &&
2537 DiagOpts.ShowSafeBufferUsageSuggestions;
2538 bool UnsafeBufferUsageShouldSuggestSuggestions =
2539 UnsafeBufferUsageCanEmitSuggestions &&
2540 !DiagOpts.ShowSafeBufferUsageSuggestions;
2541 UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions);
2544 auto CallAnalyzers = [&](
const Decl *
Node) ->
void {
2546 if (!Diags.
isIgnored(diag::warn_unsafe_buffer_operation,
2547 Node->getBeginLoc()) ||
2548 !Diags.
isIgnored(diag::warn_unsafe_buffer_variable,
2549 Node->getBeginLoc()) ||
2550 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2551 Node->getBeginLoc())) {
2553 UnsafeBufferUsageShouldEmitSuggestions);
2562 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2587 if (cast<DeclContext>(
D)->isDependentContext())
2604 AC.getCFGBuildOptions().PruneTriviallyFalseEdges =
true;
2605 AC.getCFGBuildOptions().AddEHEdges =
false;
2606 AC.getCFGBuildOptions().AddInitializers =
true;
2607 AC.getCFGBuildOptions().AddImplicitDtors =
true;
2608 AC.getCFGBuildOptions().AddTemporaryDtors =
true;
2609 AC.getCFGBuildOptions().AddCXXNewAllocator =
false;
2610 AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors =
true;
2618 if (
P.enableCheckUnreachable ||
P.enableThreadSafetyAnalysis ||
2619 P.enableConsumedAnalysis) {
2621 AC.getCFGBuildOptions().setAllAlwaysAdd();
2624 AC.getCFGBuildOptions()
2625 .setAlwaysAdd(Stmt::BinaryOperatorClass)
2626 .setAlwaysAdd(Stmt::CompoundAssignOperatorClass)
2627 .setAlwaysAdd(Stmt::BlockExprClass)
2628 .setAlwaysAdd(Stmt::CStyleCastExprClass)
2629 .setAlwaysAdd(Stmt::DeclRefExprClass)
2630 .setAlwaysAdd(Stmt::ImplicitCastExprClass)
2631 .setAlwaysAdd(Stmt::UnaryOperatorClass);
2635 std::optional<LogicalErrorHandler> LEH;
2636 if (LogicalErrorHandler::hasActiveDiagnostics(Diags,
D->
getBeginLoc())) {
2638 AC.getCFGBuildOptions().Observer = &*LEH;
2643 bool analyzed =
false;
2647 for (
const Stmt *S :
D.Stmts)
2648 AC.registerForcedBlockExpression(S);
2654 bool AllReachable =
true;
2655 for (
const Stmt *S :
D.Stmts) {
2656 const CFGBlock *block = AC.getBlockForRegisteredExpression(S);
2658 AC.getCFGReachablityAnalysis();
2664 if (!cra->
isReachable(&AC.getCFG()->getEntry(), block)) {
2665 AllReachable =
false;
2683 if (
P.enableCheckFallThrough) {
2684 const CheckFallThroughDiagnostics &CD =
2686 ? CheckFallThroughDiagnostics::MakeForBlock()
2687 : (isa<CXXMethodDecl>(
D) &&
2688 cast<CXXMethodDecl>(
D)->getOverloadedOperator() == OO_Call &&
2689 cast<CXXMethodDecl>(
D)->getParent()->isLambda())
2690 ? CheckFallThroughDiagnostics::MakeForLambda()
2692 ? CheckFallThroughDiagnostics::MakeForCoroutine(
D)
2693 : CheckFallThroughDiagnostics::MakeForFunction(
D)));
2698 if (
P.enableCheckUnreachable) {
2711 if (
P.enableThreadSafetyAnalysis) {
2714 threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
2716 Reporter.setIssueBetaWarnings(
true);
2718 Reporter.setVerbose(
true);
2722 Reporter.emitDiagnostics();
2726 if (
P.enableConsumedAnalysis) {
2727 consumed::ConsumedWarningsHandler WarningHandler(S);
2736 if (
CFG *cfg = AC.getCFG()) {
2737 UninitValsDiagReporter reporter(S);
2744 ++NumUninitAnalysisFunctions;
2747 MaxUninitAnalysisVariablesPerFunction =
2748 std::max(MaxUninitAnalysisVariablesPerFunction,
2750 MaxUninitAnalysisBlockVisitsPerFunction =
2751 std::max(MaxUninitAnalysisBlockVisitsPerFunction,
2759 shouldAnalyzeCalledOnceParameters(Diags,
D->
getBeginLoc())) {
2761 CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);
2764 shouldAnalyzeCalledOnceConventions(Diags,
D->
getBeginLoc()));
2768 bool FallThroughDiagFull =
2770 bool FallThroughDiagPerFunction = !Diags.
isIgnored(
2771 diag::warn_unannotated_fallthrough_per_function,
D->
getBeginLoc());
2772 if (FallThroughDiagFull || FallThroughDiagPerFunction ||
2783 if (!Diags.
isIgnored(diag::warn_infinite_recursive_function,
2798 if (LogicalErrorHandler::hasActiveDiagnostics(Diags,
D->
getBeginLoc())) {
2804 ++NumFunctionsAnalyzed;
2805 if (
CFG *cfg = AC.getCFG()) {
2808 NumCFGBlocks += cfg->getNumBlockIDs();
2809 MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
2810 cfg->getNumBlockIDs());
2812 ++NumFunctionsWithBadCFGs;
2818 llvm::errs() <<
"\n*** Analysis Based Warnings Stats:\n";
2820 unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
2821 unsigned AvgCFGBlocksPerFunction =
2822 !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
2823 llvm::errs() << NumFunctionsAnalyzed <<
" functions analyzed ("
2824 << NumFunctionsWithBadCFGs <<
" w/o CFGs).\n"
2825 <<
" " << NumCFGBlocks <<
" CFG blocks built.\n"
2826 <<
" " << AvgCFGBlocksPerFunction
2827 <<
" average CFG blocks per function.\n"
2828 <<
" " << MaxCFGBlocksPerFunction
2829 <<
" max CFG blocks per function.\n";
2831 unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
2832 : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
2833 unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
2834 : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
2835 llvm::errs() << NumUninitAnalysisFunctions
2836 <<
" functions analyzed for uninitialiazed variables\n"
2837 <<
" " << NumUninitAnalysisVariables <<
" variables analyzed.\n"
2838 <<
" " << AvgUninitVariablesPerFunction
2839 <<
" average variables per function.\n"
2840 <<
" " << MaxUninitAnalysisVariablesPerFunction
2841 <<
" max variables per function.\n"
2842 <<
" " << NumUninitAnalysisBlockVisits <<
" block visits.\n"
2843 <<
" " << AvgUninitBlockVisitsPerFunction
2844 <<
" average block visits per function.\n"
2845 <<
" " << MaxUninitAnalysisBlockVisitsPerFunction
2846 <<
" 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 shouldVisitImplicitCode() const
bool shouldVisitTemplateInstantiations() const
bool VisitBlockDecl(BlockDecl *Node)
bool VisitFunctionDecl(FunctionDecl *Node)
bool VisitLambdaExpr(LambdaExpr *Node)
bool VisitObjCMethodDecl(ObjCMethodDecl *Node)
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
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
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, Expr *Init)
Recursively visit a lambda capture.
bool shouldWalkTypesOfTypeLocs() const
Return whether this visitor should recurse into the types of TypeLocs.
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>'.
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.
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.
@ If
'if' clause, allowed on all the Compute Constructs, Data Constructs, Executable Constructs,...
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)
@ 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