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))
166 S.
Diag(B->
getExprLoc(), diag::warn_tautological_overlap_comparison)
167 << DiagRange << isAlwaysTrue;
171 bool isAlwaysTrue)
override {
177 << DiagRange << isAlwaysTrue;
185 S.
Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;
190 return !Diags.
isIgnored(diag::warn_tautological_overlap_comparison, Loc) ||
191 !Diags.
isIgnored(diag::warn_comparison_bitwise_or, Loc);
205 for (
const auto &B :
Block) {
219 isa<TemplateSpecializationType>(NNS->getAsType())) {
238 bool foundRecursion =
false;
243 WorkList.push_back(&cfg->
getEntry());
245 while (!WorkList.empty()) {
248 for (
auto I =
Block->succ_begin(), E =
Block->succ_end(); I != E; ++I) {
250 if (!
Visited.insert(SuccBlock).second)
254 if (ExitID == SuccBlock->getBlockID())
259 foundRecursion =
true;
263 WorkList.push_back(SuccBlock);
267 return foundRecursion;
303 Stack.push_back(&ThrowBlock);
306 while (!Stack.empty()) {
307 CFGBlock &UnwindBlock = *Stack.back();
310 for (
auto &Succ : UnwindBlock.
succs()) {
311 if (!Succ.isReachable() || Queued[Succ->getBlockID()])
318 dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
319 QualType Caught = Catch->getCaughtType();
326 Stack.push_back(Succ);
327 Queued[Succ->getBlockID()] =
true;
341 if (!Reachable[B->getBlockID()])
344 std::optional<CFGStmt> S = E.getAs<
CFGStmt>();
347 if (
auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))
357 S.
Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
359 (isa<CXXDestructorDecl>(FD) ||
363 getAs<FunctionProtoType>())
365 << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec()
388 if (FPT->isNothrow() || FD->
hasAttr<NoThrowAttr>())
429 for (
const auto *B : *cfg) {
430 if (!live[B->getBlockID()]) {
431 if (B->pred_begin() == B->pred_end()) {
432 const Stmt *Term = B->getTerminatorStmt();
433 if (Term && isa<CXXTryStmt>(Term))
445 bool HasLiveReturn =
false;
446 bool HasFakeEdge =
false;
447 bool HasPlainEdge =
false;
448 bool HasAbnormalEdge =
false;
466 HasAbnormalEdge =
true;
475 for ( ; ri != re ; ++ri)
482 if (Term && (isa<CXXTryStmt>(Term) || isa<ObjCAtTryStmt>(Term))) {
483 HasAbnormalEdge =
true;
493 if (isa<ReturnStmt>(S) || isa<CoreturnStmt>(S)) {
494 HasLiveReturn =
true;
497 if (isa<ObjCAtThrowStmt>(S)) {
501 if (isa<CXXThrowExpr>(S)) {
505 if (isa<MSAsmStmt>(S)) {
508 HasLiveReturn =
true;
511 if (isa<CXXTryStmt>(S)) {
512 HasAbnormalEdge =
true;
516 HasAbnormalEdge =
true;
527 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
537struct CheckFallThroughDiagnostics {
538 unsigned diag_MaybeFallThrough_HasNoReturn;
539 unsigned diag_MaybeFallThrough_ReturnsNonVoid;
540 unsigned diag_AlwaysFallThrough_HasNoReturn;
541 unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
542 unsigned diag_NeverFallThroughOrReturn;
546 static CheckFallThroughDiagnostics MakeForFunction(
const Decl *Func) {
547 CheckFallThroughDiagnostics D;
549 D.diag_MaybeFallThrough_HasNoReturn =
550 diag::warn_falloff_noreturn_function;
551 D.diag_MaybeFallThrough_ReturnsNonVoid =
552 diag::warn_maybe_falloff_nonvoid_function;
553 D.diag_AlwaysFallThrough_HasNoReturn =
554 diag::warn_falloff_noreturn_function;
555 D.diag_AlwaysFallThrough_ReturnsNonVoid =
556 diag::warn_falloff_nonvoid_function;
560 bool isVirtualMethod =
false;
561 if (
const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func))
562 isVirtualMethod = Method->isVirtual();
566 if (
const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func))
570 D.diag_NeverFallThroughOrReturn =
571 diag::warn_suggest_noreturn_function;
573 D.diag_NeverFallThroughOrReturn = 0;
579 static CheckFallThroughDiagnostics MakeForCoroutine(
const Decl *Func) {
580 CheckFallThroughDiagnostics D;
582 D.diag_MaybeFallThrough_HasNoReturn = 0;
583 D.diag_MaybeFallThrough_ReturnsNonVoid =
584 diag::warn_maybe_falloff_nonvoid_coroutine;
585 D.diag_AlwaysFallThrough_HasNoReturn = 0;
586 D.diag_AlwaysFallThrough_ReturnsNonVoid =
587 diag::warn_falloff_nonvoid_coroutine;
588 D.diag_NeverFallThroughOrReturn = 0;
589 D.funMode = Coroutine;
593 static CheckFallThroughDiagnostics MakeForBlock() {
594 CheckFallThroughDiagnostics D;
595 D.diag_MaybeFallThrough_HasNoReturn =
596 diag::err_noreturn_block_has_return_expr;
597 D.diag_MaybeFallThrough_ReturnsNonVoid =
598 diag::err_maybe_falloff_nonvoid_block;
599 D.diag_AlwaysFallThrough_HasNoReturn =
600 diag::err_noreturn_block_has_return_expr;
601 D.diag_AlwaysFallThrough_ReturnsNonVoid =
602 diag::err_falloff_nonvoid_block;
603 D.diag_NeverFallThroughOrReturn = 0;
608 static CheckFallThroughDiagnostics MakeForLambda() {
609 CheckFallThroughDiagnostics D;
610 D.diag_MaybeFallThrough_HasNoReturn =
611 diag::err_noreturn_lambda_has_return_expr;
612 D.diag_MaybeFallThrough_ReturnsNonVoid =
613 diag::warn_maybe_falloff_nonvoid_lambda;
614 D.diag_AlwaysFallThrough_HasNoReturn =
615 diag::err_noreturn_lambda_has_return_expr;
616 D.diag_AlwaysFallThrough_ReturnsNonVoid =
617 diag::warn_falloff_nonvoid_lambda;
618 D.diag_NeverFallThroughOrReturn = 0;
624 bool HasNoReturn)
const {
625 if (funMode == Function) {
626 return (ReturnsVoid ||
627 D.
isIgnored(diag::warn_maybe_falloff_nonvoid_function,
630 D.
isIgnored(diag::warn_noreturn_function_has_return_expr,
633 D.
isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));
635 if (funMode == Coroutine) {
636 return (ReturnsVoid ||
637 D.
isIgnored(diag::warn_maybe_falloff_nonvoid_function, FuncLoc) ||
638 D.
isIgnored(diag::warn_maybe_falloff_nonvoid_coroutine,
643 return ReturnsVoid && !HasNoReturn;
655 const CheckFallThroughDiagnostics &CD,
659 bool ReturnsVoid =
false;
660 bool HasNoReturn =
false;
663 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
664 if (
const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
665 ReturnsVoid = CBody->getFallthroughHandler() !=
nullptr;
667 ReturnsVoid = FD->getReturnType()->isVoidType();
668 HasNoReturn = FD->isNoReturn();
670 else if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
671 ReturnsVoid = MD->getReturnType()->isVoidType();
672 HasNoReturn = MD->hasAttr<NoReturnAttr>();
674 else if (isa<BlockDecl>(D)) {
677 if (FT->getReturnType()->isVoidType())
679 if (FT->getNoReturnAttr())
687 if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
708 EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);
709 else if (!ReturnsVoid)
710 EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);
714 EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);
715 else if (!ReturnsVoid)
716 EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
719 if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
720 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
721 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
722 }
else if (
const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
723 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
725 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
750 : Inherited(Context), FoundReference(
false), Needle(Needle) {}
752 void VisitExpr(
const Expr *E) {
757 Inherited::VisitExpr(E);
762 FoundReference =
true;
767 bool doesContainReference()
const {
return FoundReference; }
775 S.
Diag(VD->
getLocation(), diag::note_block_var_fixit_add_initialization)
796 S.
Diag(Loc, diag::note_var_fixit_add_initialization) << VD->
getDeclName()
804 const Stmt *Else,
bool CondVal,
828 bool IsCapturedByBlock) {
829 bool Diagnosed =
false;
862 const Stmt *Term = I->Terminator;
872 int RemoveDiagKind = -1;
873 const char *FixitStr =
874 S.
getLangOpts().CPlusPlus ? (I->Output ?
"true" :
"false")
875 : (I->Output ?
"1" :
"0");
878 switch (Term ? Term->
getStmtClass() : Stmt::DeclStmtClass) {
885 case Stmt::IfStmtClass: {
886 const IfStmt *IS = cast<IfStmt>(Term);
892 I->Output, Fixit1, Fixit2);
895 case Stmt::ConditionalOperatorClass: {
902 I->Output, Fixit1, Fixit2);
905 case Stmt::BinaryOperatorClass: {
913 if ((BO->
getOpcode() == BO_LAnd && I->Output) ||
914 (BO->
getOpcode() == BO_LOr && !I->Output))
925 case Stmt::WhileStmtClass:
928 Range = cast<WhileStmt>(Term)->getCond()->getSourceRange();
932 case Stmt::ForStmtClass:
935 Range = cast<ForStmt>(Term)->getCond()->getSourceRange();
942 case Stmt::CXXForRangeStmtClass:
943 if (I->Output == 1) {
951 Range = cast<CXXForRangeStmt>(Term)->getRangeInit()->getSourceRange();
955 case Stmt::DoStmtClass:
958 Range = cast<DoStmt>(Term)->getCond()->getSourceRange();
964 case Stmt::CaseStmtClass:
967 Range = cast<CaseStmt>(Term)->getLHS()->getSourceRange();
969 case Stmt::DefaultStmtClass:
972 Range = cast<DefaultStmt>(Term)->getDefaultLoc();
976 S.
Diag(Range.getBegin(), diag::warn_sometimes_uninit_var)
977 << VD->
getDeclName() << IsCapturedByBlock << DiagKind
978 << Str << I->Output << Range;
981 if (RemoveDiagKind != -1)
983 << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
1009 bool alwaysReportSelfInit =
false) {
1023 if (!alwaysReportSelfInit && DRE ==
Initializer->IgnoreParenImpCasts())
1026 ContainsReference CR(S.
Context, DRE);
1028 if (CR.doesContainReference()) {
1029 S.
Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
1040 diag::warn_uninit_byref_blockvar_captured_by_block)
1060 FallthroughMapper(
Sema &S)
1061 : FoundSwitchStatements(
false),
1065 bool foundSwitchStatements()
const {
return FoundSwitchStatements; }
1068 bool Found = FallthroughStmts.erase(
Stmt);
1075 const AttrStmts &getFallthroughStmts()
const {
1076 return FallthroughStmts;
1079 void fillReachableBlocks(
CFG *Cfg) {
1080 assert(ReachableBlocks.empty() &&
"ReachableBlocks already filled");
1081 std::deque<const CFGBlock *> BlockQueue;
1083 ReachableBlocks.insert(&Cfg->
getEntry());
1084 BlockQueue.push_back(&Cfg->
getEntry());
1089 for (
const auto *B : *Cfg) {
1090 const Stmt *L = B->getLabel();
1091 if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B).second)
1092 BlockQueue.push_back(B);
1095 while (!BlockQueue.empty()) {
1097 BlockQueue.pop_front();
1099 if (B && ReachableBlocks.insert(B).second)
1100 BlockQueue.push_back(B);
1105 bool checkFallThroughIntoBlock(
const CFGBlock &B,
int &AnnotatedCnt,
1106 bool IsTemplateInstantiation) {
1107 assert(!ReachableBlocks.empty() &&
"ReachableBlocks empty");
1109 int UnannotatedCnt = 0;
1113 while (!BlockQueue.empty()) {
1115 BlockQueue.pop_front();
1118 const Stmt *Term =
P->getTerminatorStmt();
1119 if (Term && isa<SwitchStmt>(Term))
1122 const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(
P->getLabel());
1126 const LabelStmt *L = dyn_cast_or_null<LabelStmt>(
P->getLabel());
1130 if (!ReachableBlocks.count(
P)) {
1131 for (
const CFGElement &Elem : llvm::reverse(*
P)) {
1132 if (std::optional<CFGStmt> CS = Elem.getAs<
CFGStmt>()) {
1133 if (
const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
1137 if (!IsTemplateInstantiation)
1138 S.
Diag(AS->getBeginLoc(),
1139 diag::warn_unreachable_fallthrough_attr);
1140 markFallthroughVisited(AS);
1160 markFallthroughVisited(AS);
1167 std::copy(
P->pred_begin(),
P->pred_end(),
1168 std::back_inserter(BlockQueue));
1174 return !!UnannotatedCnt;
1181 if (asFallThroughAttr(S))
1182 FallthroughStmts.insert(S);
1187 FoundSwitchStatements =
true;
1198 for (
const auto C : zip(
LE->captures(),
LE->capture_inits()))
1206 if (
const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
1207 if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs()))
1216 for (
const CFGElement &Elem : llvm::reverse(B))
1217 if (std::optional<CFGStmt> CS = Elem.getAs<
CFGStmt>())
1218 return CS->getStmt();
1229 bool FoundSwitchStatements;
1230 AttrStmts FallthroughStmts;
1239 tok::l_square, tok::l_square,
1241 tok::r_square, tok::r_square
1247 tok::r_square, tok::r_square
1252 StringRef MacroName;
1253 if (PreferClangAttr)
1255 if (MacroName.empty())
1257 if (MacroName.empty() && !PreferClangAttr)
1259 if (MacroName.empty()) {
1260 if (!PreferClangAttr)
1261 MacroName =
"[[fallthrough]]";
1263 MacroName =
"[[clang::fallthrough]]";
1265 MacroName =
"__attribute__((fallthrough))";
1272 FallthroughMapper FM(S);
1273 FM.TraverseStmt(AC.
getBody());
1275 if (!FM.foundSwitchStatements())
1278 if (PerFunction && FM.getFallthroughStmts().empty())
1286 FM.fillReachableBlocks(Cfg);
1288 for (
const CFGBlock *B : llvm::reverse(*Cfg)) {
1291 if (!isa_and_nonnull<SwitchCase>(
Label))
1296 bool IsTemplateInstantiation =
false;
1298 IsTemplateInstantiation = Function->isTemplateInstantiation();
1299 if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,
1300 IsTemplateInstantiation))
1304 PerFunction ? diag::warn_unannotated_fallthrough_per_function
1305 : diag::warn_unannotated_fallthrough);
1307 if (!AnnotatedCnt) {
1318 if (!(B->
empty() && Term && isa<BreakStmt>(Term))) {
1322 TextToInsert +=
"; ";
1323 S.
Diag(L, diag::note_insert_fallthrough_fixit)
1324 << AnnotationSpelling
1327 S.
Diag(L, diag::note_insert_break_fixit)
1332 for (
const auto *F : FM.getFallthroughStmts())
1333 S.
Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement);
1341 switch (S->getStmtClass()) {
1342 case Stmt::ForStmtClass:
1343 case Stmt::WhileStmtClass:
1344 case Stmt::CXXForRangeStmtClass:
1345 case Stmt::ObjCForCollectionStmtClass:
1347 case Stmt::DoStmtClass: {
1349 if (!cast<DoStmt>(S)->getCond()->
EvaluateAsInt(Result, Ctx))
1351 return Result.Val.getInt().getBoolValue();
1368 typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
1377 for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end();
1379 const WeakUseVector &Uses = I->second;
1382 WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
1383 for ( ; UI != UE; ++UI) {
1396 if (UI == Uses.begin()) {
1397 WeakUseVector::const_iterator UI2 = UI;
1398 for (++UI2; UI2 != UE; ++UI2)
1399 if (UI2->isUnsafe())
1403 if (!
isInLoop(Ctx, PM, UI->getUseExpr()))
1406 const WeakObjectProfileTy &Profile = I->first;
1407 if (!Profile.isExactProfile())
1412 Base = Profile.getProperty();
1413 assert(
Base &&
"A profile always has a base or property.");
1415 if (
const VarDecl *BaseVar = dyn_cast<VarDecl>(
Base))
1416 if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(
Base))
1421 UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
1424 if (UsesByStmt.empty())
1429 llvm::sort(UsesByStmt,
1430 [&
SM](
const StmtUsesPair &LHS,
const StmtUsesPair &RHS) {
1432 RHS.first->getBeginLoc());
1447 if (isa<sema::BlockScopeInfo>(CurFn))
1448 FunctionKind =
Block;
1449 else if (isa<sema::LambdaScopeInfo>(CurFn))
1450 FunctionKind = Lambda;
1451 else if (isa<ObjCMethodDecl>(D))
1452 FunctionKind = Method;
1454 FunctionKind = Function;
1457 for (
const auto &
P : UsesByStmt) {
1458 const Stmt *FirstRead =
P.first;
1459 const WeakObjectProfileTy &Key =
P.second->first;
1460 const WeakUseVector &Uses =
P.second->second;
1468 if (Key.isExactProfile())
1469 DiagKind = diag::warn_arc_repeated_use_of_weak;
1471 DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
1483 const NamedDecl *KeyProp = Key.getProperty();
1484 if (isa<VarDecl>(KeyProp))
1485 ObjectKind = Variable;
1486 else if (isa<ObjCPropertyDecl>(KeyProp))
1488 else if (isa<ObjCMethodDecl>(KeyProp))
1489 ObjectKind = ImplicitProperty;
1490 else if (isa<ObjCIvarDecl>(KeyProp))
1493 llvm_unreachable(
"Unexpected weak object kind!");
1498 if (Prop->hasAttr<IBOutletAttr>())
1503 <<
int(ObjectKind) << KeyProp <<
int(FunctionKind)
1507 for (
const auto &Use : Uses) {
1508 if (Use.getUseExpr() == FirstRead)
1510 S.
Diag(Use.getUseExpr()->getBeginLoc(),
1511 diag::note_arc_weak_also_accessed_here)
1512 << Use.getUseExpr()->getSourceRange();
1520typedef std::pair<PartialDiagnosticAt, OptionalNotes>
DelayedDiag;
1521typedef std::list<DelayedDiag>
DiagList;
1523struct SortDiagBySourceLocation {
1527 bool operator()(
const DelayedDiag &left,
const DelayedDiag &right) {
1530 return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
1540 typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
1544 typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
1546 UsesMap constRefUses;
1549 UninitValsDiagReporter(
Sema &S) : S(S) {}
1552 MappedType &getUses(UsesMap &um,
const VarDecl *vd) {
1553 MappedType &
V = um[vd];
1554 if (!
V.getPointer())
1555 V.setPointer(
new UsesVec());
1561 getUses(uses, vd).getPointer()->push_back(use);
1566 getUses(constRefUses, vd).getPointer()->push_back(use);
1570 getUses(uses, vd).setInt(
true);
1571 getUses(constRefUses, vd).setInt(
true);
1575 for (
const auto &
P : uses) {
1577 const MappedType &
V =
P.second;
1579 UsesVec *vec =
V.getPointer();
1580 bool hasSelfInit =
V.getInt();
1585 if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
1601 for (
const auto &
U : *vec) {
1619 for (
const auto &
P : constRefUses) {
1621 const MappedType &
V =
P.second;
1623 UsesVec *vec =
V.getPointer();
1624 bool hasSelfInit =
V.getInt();
1626 if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
1632 for (
const auto &
U : *vec) {
1642 constRefUses.clear();
1646 static bool hasAlwaysUninitializedUse(
const UsesVec* vec) {
1647 return llvm::any_of(*vec, [](
const UninitUse &
U) {
1656class CalledOnceInterProceduralData {
1661 DelayedBlockWarnings[
Block].emplace_back(std::move(
Warning));
1666 S.
Diag(Delayed.first, Delayed.second);
1668 discardWarnings(
Block);
1672 DelayedBlockWarnings.erase(
Block);
1677 llvm::DenseMap<const BlockDecl *, DelayedDiagnostics> DelayedBlockWarnings;
1682 CalledOnceCheckReporter(
Sema &S, CalledOnceInterProceduralData &Data)
1685 const Expr *PrevCall,
bool IsCompletionHandler,
1686 bool Poised)
override {
1687 auto DiagToReport = IsCompletionHandler
1688 ? diag::warn_completion_handler_called_twice
1689 : diag::warn_called_once_gets_called_twice;
1691 S.
Diag(PrevCall->
getBeginLoc(), diag::note_called_once_gets_called_twice)
1696 bool IsCompletionHandler)
override {
1697 auto DiagToReport = IsCompletionHandler
1698 ? diag::warn_completion_handler_never_called
1699 : diag::warn_called_once_never_called;
1706 bool IsCalledDirectly,
1707 bool IsCompletionHandler)
override {
1708 auto DiagToReport = IsCompletionHandler
1709 ? diag::warn_completion_handler_never_called_when
1710 : diag::warn_called_once_never_called_when;
1714 << (
unsigned)Reason);
1716 if (
const auto *
Block = dyn_cast<BlockDecl>(Function)) {
1726 bool IsCompletionHandler)
override {
1727 auto DiagToReport = IsCompletionHandler
1728 ? diag::warn_completion_handler_never_called
1729 : diag::warn_called_once_never_called;
1745 CalledOnceInterProceduralData &
Data;
1748constexpr unsigned CalledOnceWarnings[] = {
1749 diag::warn_called_once_never_called,
1750 diag::warn_called_once_never_called_when,
1751 diag::warn_called_once_gets_called_twice};
1753constexpr unsigned CompletionHandlerWarnings[]{
1754 diag::warn_completion_handler_never_called,
1755 diag::warn_completion_handler_never_called_when,
1756 diag::warn_completion_handler_called_twice};
1761 return llvm::any_of(DiagIDs, [&Diags, At](
unsigned DiagID) {
1768 return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);
1773 return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||
1774 shouldAnalyzeCalledOnceConventions(Diags, At);
1782namespace threadSafety {
1793 if (Verbose && CurrentFunction) {
1795 S.
PDiag(diag::note_thread_warning_in_fun)
1796 << CurrentFunction);
1804 if (Verbose && CurrentFunction) {
1806 S.
PDiag(diag::note_thread_warning_in_fun)
1807 << CurrentFunction);
1808 ONS.push_back(std::move(FNote));
1816 ONS.push_back(Note1);
1817 ONS.push_back(Note2);
1818 if (Verbose && CurrentFunction) {
1820 S.
PDiag(diag::note_thread_warning_in_fun)
1821 << CurrentFunction);
1822 ONS.push_back(std::move(FNote));
1830 LocLocked, S.
PDiag(diag::note_locked_here) << Kind))
1838 LocUnlocked, S.
PDiag(diag::note_unlocked_here) << Kind))
1844 : S(S), FunLocation(FL), FunEndLocation(FEL),
1845 CurrentFunction(nullptr), Verbose(
false) {}
1847 void setVerbose(
bool b) { Verbose =
b; }
1855 for (
const auto &
Diag : Warnings) {
1857 for (
const auto &
Note :
Diag.second)
1865 Warnings.emplace_back(std::move(
Warning), getNotes());
1868 void handleUnmatchedUnlock(StringRef Kind, Name LockName,
SourceLocation Loc,
1873 << Kind << LockName);
1874 Warnings.emplace_back(std::move(
Warning),
1875 makeUnlockedHereNote(LocPreviousUnlock, Kind));
1878 void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
1883 LocUnlock = FunLocation;
1885 LocUnlock, S.
PDiag(diag::warn_unlock_kind_mismatch)
1886 << Kind << LockName << Received <<
Expected);
1887 Warnings.emplace_back(std::move(
Warning),
1888 makeLockedHereNote(LocLocked, Kind));
1891 void handleDoubleLock(StringRef Kind, Name LockName,
SourceLocation LocLocked,
1894 LocDoubleLock = FunLocation;
1896 << Kind << LockName);
1897 Warnings.emplace_back(std::move(
Warning),
1898 makeLockedHereNote(LocLocked, Kind));
1901 void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
1905 unsigned DiagID = 0;
1908 DiagID = diag::warn_lock_some_predecessors;
1911 DiagID = diag::warn_expecting_lock_held_on_loop;
1914 DiagID = diag::warn_no_unlock;
1917 DiagID = diag::warn_expecting_locked;
1921 LocEndOfScope = FunEndLocation;
1925 Warnings.emplace_back(std::move(
Warning),
1926 makeLockedHereNote(LocLocked, Kind));
1929 void handleExclusiveAndShared(StringRef Kind, Name LockName,
1933 S.
PDiag(diag::warn_lock_exclusive_and_shared)
1934 << Kind << LockName);
1936 << Kind << LockName);
1937 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
1943 "Only works for variables");
1945 diag::warn_variable_requires_any_lock:
1946 diag::warn_var_deref_requires_any_lock;
1949 Warnings.emplace_back(std::move(
Warning), getNotes());
1952 void handleMutexNotHeld(StringRef Kind,
const NamedDecl *D,
1955 Name *PossibleMatch)
override {
1956 unsigned DiagID = 0;
1957 if (PossibleMatch) {
1960 DiagID = diag::warn_variable_requires_lock_precise;
1963 DiagID = diag::warn_var_deref_requires_lock_precise;
1966 DiagID = diag::warn_fun_requires_lock_precise;
1969 DiagID = diag::warn_guarded_pass_by_reference;
1972 DiagID = diag::warn_pt_guarded_pass_by_reference;
1982 S.
PDiag(diag::note_guarded_by_declared_here)
1984 Warnings.emplace_back(std::move(
Warning), getNotes(
Note, VNote));
1986 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
1990 DiagID = diag::warn_variable_requires_lock;
1993 DiagID = diag::warn_var_deref_requires_lock;
1996 DiagID = diag::warn_fun_requires_lock;
1999 DiagID = diag::warn_guarded_pass_by_reference;
2002 DiagID = diag::warn_pt_guarded_pass_by_reference;
2010 S.
PDiag(diag::note_guarded_by_declared_here));
2011 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2013 Warnings.emplace_back(std::move(
Warning), getNotes());
2017 void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
2020 S.
PDiag(diag::warn_acquire_requires_negative_cap)
2021 << Kind << LockName << Neg);
2022 Warnings.emplace_back(std::move(
Warning), getNotes());
2025 void handleNegativeNotHeld(
const NamedDecl *D, Name LockName,
2028 Loc, S.
PDiag(diag::warn_fun_requires_negative_cap) << D << LockName);
2029 Warnings.emplace_back(std::move(
Warning), getNotes());
2032 void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
2035 << Kind << FunName << LockName);
2036 Warnings.emplace_back(std::move(
Warning), getNotes());
2039 void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
2042 S.
PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
2043 Warnings.emplace_back(std::move(
Warning), getNotes());
2046 void handleBeforeAfterCycle(Name L1Name,
SourceLocation Loc)
override {
2048 S.
PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
2049 Warnings.emplace_back(std::move(
Warning), getNotes());
2053 CurrentFunction = FD;
2057 CurrentFunction =
nullptr;
2071class ConsumedWarningsHandler :
public ConsumedWarningsHandlerBase {
2078 ConsumedWarningsHandler(
Sema &S) : S(S) {}
2082 for (
const auto &
Diag : Warnings) {
2084 for (
const auto &
Note :
Diag.second)
2090 StringRef VariableName)
override {
2098 StringRef VariableName,
2099 StringRef ExpectedState,
2100 StringRef ObservedState)
override {
2103 diag::warn_param_return_typestate_mismatch) << VariableName <<
2104 ExpectedState << ObservedState);
2109 void warnParamTypestateMismatch(
SourceLocation Loc, StringRef ExpectedState,
2110 StringRef ObservedState)
override {
2113 diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
2119 StringRef TypeName)
override {
2121 diag::warn_return_typestate_for_unconsumable_type) << TypeName);
2126 void warnReturnTypestateMismatch(
SourceLocation Loc, StringRef ExpectedState,
2127 StringRef ObservedState)
override {
2130 diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
2135 void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
2139 diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
2144 void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
2148 MethodName << VariableName << State);
2164 bool SuggestSuggestions;
2167 UnsafeBufferUsageReporter(
Sema &S,
bool SuggestSuggestions)
2168 : S(S), SuggestSuggestions(SuggestSuggestions) {}
2171 bool IsRelatedToDecl)
override {
2174 unsigned MsgParam = 0;
2175 if (
const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
2176 Loc = ASE->getBase()->getExprLoc();
2177 Range = ASE->getBase()->getSourceRange();
2179 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
2181 if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
2182 Op == BO_SubAssign) {
2183 if (BO->getRHS()->getType()->isIntegerType()) {
2184 Loc = BO->getLHS()->getExprLoc();
2185 Range = BO->getLHS()->getSourceRange();
2187 Loc = BO->getRHS()->getExprLoc();
2188 Range = BO->getRHS()->getSourceRange();
2192 }
else if (
const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
2194 if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
2196 Loc = UO->getSubExpr()->getExprLoc();
2197 Range = UO->getSubExpr()->getSourceRange();
2201 if (isa<CallExpr>(Operation)) {
2203 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2209 if (IsRelatedToDecl) {
2210 assert(!SuggestSuggestions &&
2211 "Variables blamed for unsafe buffer usage without suggestions!");
2212 S.
Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2214 S.
Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam <<
Range;
2215 if (SuggestSuggestions) {
2216 S.
Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled);
2223 FixItList &&Fixes)
override {
2224 assert(!SuggestSuggestions &&
2225 "Unsafe buffer usage fixits displayed without suggestions!");
2226 S.
Diag(
Variable->getLocation(), diag::warn_unsafe_buffer_variable)
2229 if (!Fixes.empty()) {
2230 const auto VarGroupForVD = VarGrpMap.find(Variable)->second;
2231 unsigned FixItStrategy = 0;
2233 diag::note_unsafe_buffer_variable_fixit_group);
2236 std::string AllVars =
"";
2237 if (VarGroupForVD.size() > 1) {
2238 if (VarGroupForVD.size() == 2) {
2239 if (VarGroupForVD[0] == Variable) {
2240 AllVars.append(
"'" + VarGroupForVD[1]->
getName().str() +
"'");
2242 AllVars.append(
"'" + VarGroupForVD[0]->
getName().str() +
"'");
2246 if (VarGroupForVD.size() == 3) {
2247 for (
const VarDecl *
V : VarGroupForVD) {
2248 if (
V == Variable) {
2253 AllVars.append(
"'" +
V->getName().str() +
"'" +
" and ");
2255 AllVars.append(
"'" +
V->getName().str() +
"'");
2259 for (
const VarDecl *
V : VarGroupForVD) {
2260 if (
V == Variable) {
2263 if (VarGroupForVD.back() !=
V) {
2264 AllVars.append(
"'" +
V->getName().str() +
"'" +
", ");
2266 AllVars.append(
"and '" +
V->getName().str() +
"'");
2276 for (
const auto &F : Fixes)
2293 enableCheckFallThrough = 1;
2294 enableCheckUnreachable = 0;
2295 enableThreadSafetyAnalysis = 0;
2296 enableConsumedAnalysis = 0;
2323 NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),
2324 MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),
2325 NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
2326 NumUninitAnalysisBlockVisits(0),
2327 MaxUninitAnalysisBlockVisitsPerFunction(0) {
2329 using namespace diag;
2332 DefaultPolicy.enableCheckUnreachable =
2334 isEnabled(D, warn_unreachable_return) ||
2335 isEnabled(D, warn_unreachable_loop_increment);
2337 DefaultPolicy.enableThreadSafetyAnalysis =
isEnabled(D, warn_double_lock);
2339 DefaultPolicy.enableConsumedAnalysis =
2340 isEnabled(D, warn_use_in_invalid_state);
2348 S.
Diag(D.Loc, D.PD);
2355 llvm::function_ref<void(
const Decl *)> Callback;
2359 : Callback(Callback) {}
2362 if (cast<DeclContext>(
Node)->isDependentContext())
2367 if (
Node->doesThisDeclarationHaveABody())
2373 if (cast<DeclContext>(
Node)->isDependentContext())
2380 if (cast<DeclContext>(
Node)->isDependentContext())
2382 if (
Node->hasBody())
2388 return VisitFunctionDecl(
Node->getCallOperator());
2409 bool UnsafeBufferUsageCanEmitSuggestions = S.
getLangOpts().CPlusPlus20;
2410 bool UnsafeBufferUsageShouldEmitSuggestions =
2411 UnsafeBufferUsageCanEmitSuggestions &&
2412 DiagOpts.ShowSafeBufferUsageSuggestions;
2413 bool UnsafeBufferUsageShouldSuggestSuggestions =
2414 UnsafeBufferUsageCanEmitSuggestions &&
2415 !DiagOpts.ShowSafeBufferUsageSuggestions;
2416 UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions);
2419 auto CallAnalyzers = [&](
const Decl *
Node) ->
void {
2421 if (!Diags.
isIgnored(diag::warn_unsafe_buffer_operation,
2422 Node->getBeginLoc()) ||
2423 !Diags.
isIgnored(diag::warn_unsafe_buffer_variable,
2424 Node->getBeginLoc())) {
2426 UnsafeBufferUsageShouldEmitSuggestions);
2458 if (cast<DeclContext>(D)->isDependentContext())
2489 if (
P.enableCheckUnreachable ||
P.enableThreadSafetyAnalysis ||
2490 P.enableConsumedAnalysis) {
2506 std::optional<LogicalErrorHandler> LEH;
2507 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->
getBeginLoc())) {
2514 bool analyzed =
false;
2518 for (
const Stmt *S : D.Stmts)
2525 bool AllReachable =
true;
2526 for (
const Stmt *S : D.Stmts) {
2536 AllReachable =
false;
2545 S.
Diag(D.Loc, D.PD);
2554 if (
P.enableCheckFallThrough) {
2555 const CheckFallThroughDiagnostics &CD =
2557 ? CheckFallThroughDiagnostics::MakeForBlock()
2558 : (isa<CXXMethodDecl>(D) &&
2559 cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call &&
2560 cast<CXXMethodDecl>(D)->getParent()->isLambda())
2561 ? CheckFallThroughDiagnostics::MakeForLambda()
2563 ? CheckFallThroughDiagnostics::MakeForCoroutine(D)
2564 : CheckFallThroughDiagnostics::MakeForFunction(D)));
2569 if (
P.enableCheckUnreachable) {
2575 if (
const FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
2582 if (
P.enableThreadSafetyAnalysis) {
2585 threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
2587 Reporter.setIssueBetaWarnings(
true);
2589 Reporter.setVerbose(
true);
2593 Reporter.emitDiagnostics();
2597 if (
P.enableConsumedAnalysis) {
2598 consumed::ConsumedWarningsHandler WarningHandler(S);
2608 UninitValsDiagReporter reporter(S);
2615 ++NumUninitAnalysisFunctions;
2618 MaxUninitAnalysisVariablesPerFunction =
2619 std::max(MaxUninitAnalysisVariablesPerFunction,
2621 MaxUninitAnalysisBlockVisitsPerFunction =
2622 std::max(MaxUninitAnalysisBlockVisitsPerFunction,
2630 shouldAnalyzeCalledOnceParameters(Diags, D->
getBeginLoc())) {
2632 CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);
2635 shouldAnalyzeCalledOnceConventions(Diags, D->
getBeginLoc()));
2639 bool FallThroughDiagFull =
2641 bool FallThroughDiagPerFunction = !Diags.
isIgnored(
2642 diag::warn_unannotated_fallthrough_per_function, D->
getBeginLoc());
2643 if (FallThroughDiagFull || FallThroughDiagPerFunction ||
2654 if (!Diags.
isIgnored(diag::warn_infinite_recursive_function,
2656 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
2663 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
2669 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->
getBeginLoc())) {
2675 ++NumFunctionsAnalyzed;
2680 MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
2681 cfg->getNumBlockIDs());
2683 ++NumFunctionsWithBadCFGs;
2689 llvm::errs() <<
"\n*** Analysis Based Warnings Stats:\n";
2691 unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
2692 unsigned AvgCFGBlocksPerFunction =
2693 !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
2694 llvm::errs() << NumFunctionsAnalyzed <<
" functions analyzed ("
2695 << NumFunctionsWithBadCFGs <<
" w/o CFGs).\n"
2696 <<
" " << NumCFGBlocks <<
" CFG blocks built.\n"
2697 <<
" " << AvgCFGBlocksPerFunction
2698 <<
" average CFG blocks per function.\n"
2699 <<
" " << MaxCFGBlocksPerFunction
2700 <<
" max CFG blocks per function.\n";
2702 unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
2703 : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
2704 unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
2705 : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
2706 llvm::errs() << NumUninitAnalysisFunctions
2707 <<
" functions analyzed for uninitialiazed variables\n"
2708 <<
" " << NumUninitAnalysisVariables <<
" variables analyzed.\n"
2709 <<
" " << AvgUninitVariablesPerFunction
2710 <<
" average variables per function.\n"
2711 <<
" " << MaxUninitAnalysisVariablesPerFunction
2712 <<
" max variables per function.\n"
2713 <<
" " << NumUninitAnalysisBlockVisits <<
" block visits.\n"
2714 <<
" " << AvgUninitBlockVisitsPerFunction
2715 <<
" average block visits per function.\n"
2716 <<
" " << MaxUninitAnalysisBlockVisitsPerFunction
2717 <<
" 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.
static std::string getName(const CallEvent &Call)
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 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 ...
AnalysisDeclContext contains the context data for the function, method or block under analysis.
void registerForcedBlockExpression(const Stmt *stmt)
const CFGBlock * getBlockForRegisteredExpression(const Stmt *stmt)
ParentMap & getParentMap()
const Decl * getDecl() const
bool getAddEHEdges() const
CFGReverseBlockReachabilityAnalysis * getCFGReachablityAnalysis()
CFG::BuildOptions & getCFGBuildOptions()
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 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
bool PruneTriviallyFalseEdges
bool AddCXXDefaultInitExprInCtors
BuildOptions & setAllAlwaysAdd()
BuildOptions & setAlwaysAdd(Stmt::StmtClass stmtClass, bool val=true)
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]).
const Expr * getSubExpr() const
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.
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.
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.
Sema - This implements semantic analysis and AST building for C.
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
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.
PartialDiagnostic PDiag(unsigned DiagID=0)
Build a partial diagnostic.
SourceManager & SourceMgr
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
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...
virtual void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl)=0
Invoked when an unsafe operation over raw pointers is found.
virtual void handleUnsafeVariableGroup(const VarDecl *Variable, const DefMapTy &VarGrpMap, FixItList &&Fixes)=0
Invoked when a fix is suggested against a variable.
virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const =0
Returns a reference to the Preprocessor:
Represents a variable declaration or definition.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
const Expr * getInit() const
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
uint32_t Variable
Boolean variables are represented as positive integers.
bool Call(InterpState &S, CodePtr OpPC, const Function *Func)
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_VarAccess
Reading or writing a variable (e.g. x in x = 5;)
@ POK_FunctionCall
Making a function call (e.g. fool())
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)
llvm::DenseMap< const VarDecl *, std::vector< const VarDecl * > > DefMapTy
@ C
Languages that the frontend can parse and compile.
@ 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