48#include "llvm/ADT/ArrayRef.h"
49#include "llvm/ADT/BitVector.h"
50#include "llvm/ADT/DenseMap.h"
51#include "llvm/ADT/MapVector.h"
52#include "llvm/ADT/STLFunctionalExtras.h"
53#include "llvm/ADT/SmallVector.h"
54#include "llvm/ADT/StringRef.h"
55#include "llvm/Support/Debug.h"
73 UnreachableCodeHandler(
Sema &
s) : S(
s) {}
81 if (HasFallThroughAttr &&
88 if (PreviousSilenceableCondVal.
isValid() &&
90 PreviousSilenceableCondVal == SilenceableCondVal)
92 PreviousSilenceableCondVal = SilenceableCondVal;
94 unsigned diag = diag::warn_unreachable;
97 diag = diag::warn_unreachable_break;
100 diag = diag::warn_unreachable_return;
103 diag = diag::warn_unreachable_loop_increment;
109 S.
Diag(L, diag) << R1 << R2;
112 if (
Open.isValid()) {
116 S.
Diag(
Open, diag::note_unreachable_silence)
137 UnreachableCodeHandler UC(S);
147 LogicalErrorHandler(
Sema &S) : S(S) {}
149 static bool HasMacroID(
const Expr *
E) {
155 if (
const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt))
156 if (HasMacroID(SubExpr))
166 unsigned DiagID = isAlwaysTrue
167 ? diag::warn_tautological_negation_or_compare
168 : diag::warn_tautological_negation_and_compare;
174 bool isAlwaysTrueOrFalse)
override {
179 S.
Diag(B->
getExprLoc(), diag::warn_tautological_overlap_comparison)
180 << DiagRange << isAlwaysTrueOrFalse;
184 bool isAlwaysTrue)
override {
190 << DiagRange << isAlwaysTrue;
198 S.
Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;
203 return !Diags.
isIgnored(diag::warn_tautological_overlap_comparison,
Loc) ||
204 !Diags.
isIgnored(diag::warn_comparison_bitwise_or,
Loc) ||
205 !Diags.
isIgnored(diag::warn_tautological_negation_and_compare,
Loc);
219 for (
const auto &B :
Block) {
232 NNS.
getKind() == NestedNameSpecifier::Kind::Type)
233 if (isa_and_nonnull<TemplateSpecializationType>(NNS.getAsType()))
249 bool foundRecursion =
false;
254 WorkList.push_back(&cfg->
getEntry());
256 while (!WorkList.empty()) {
261 if (!
Visited.insert(SuccBlock).second)
265 if (ExitID == SuccBlock->getBlockID())
270 foundRecursion =
true;
274 WorkList.push_back(SuccBlock);
278 return foundRecursion;
291 CFG *cfg = AC.getCFG();
314 Stack.push_back(&ThrowBlock);
317 while (!Stack.empty()) {
318 CFGBlock &UnwindBlock = *Stack.pop_back_val();
320 for (
auto &Succ : UnwindBlock.
succs()) {
321 if (!Succ.isReachable() || Queued[Succ->getBlockID()])
328 dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
329 QualType Caught = Catch->getCaughtType();
336 Stack.push_back(Succ);
337 Queued[Succ->getBlockID()] =
true;
351 if (!Reachable[B->getBlockID()])
354 std::optional<CFGStmt> S =
E.getAs<
CFGStmt>();
357 if (
auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))
367 S.
Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
369 (isa<CXXDestructorDecl>(FD) ||
373 getAs<FunctionProtoType>())
375 << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec()
385 CFG *BodyCFG = AC.getCFG();
398 if (FPT->isNothrow() || FD->
hasAttr<NoThrowAttr>())
407 if (
auto *FD = dyn_cast<FunctionDecl>(DRef->getDecl()))
408 return FD->isNoReturn();
427struct TransferFunctions :
public StmtVisitor<TransferFunctions> {
429 std::optional<bool> AllValuesAreNoReturn;
431 TransferFunctions(
const VarDecl *VD) : Var(VD) {}
433 void reset() { AllValuesAreNoReturn = std::nullopt; }
436 for (
auto *DI : DS->
decls())
437 if (
auto *VD = dyn_cast<VarDecl>(DI))
447 if (DRef->getDecl() == Var)
448 AllValuesAreNoReturn =
false;
455 if (DRef->getDecl() == Var)
462 const Expr *Arg = *I;
465 if (
auto VD = dyn_cast<VarDecl>(DRef->getDecl()))
466 if (VD->getDefinition() == Var)
467 AllValuesAreNoReturn =
false;
493 using MapTy = llvm::DenseMap<const CFGBlock *, std::optional<bool>>;
494 using ValueTy = MapTy::value_type;
496 BlocksToCheck[&VarBlk] = std::nullopt;
497 const auto BlockSatisfiesCondition = [](ValueTy Item) {
498 return Item.getSecond().value_or(
false);
501 TransferFunctions TF(VD);
503 llvm::DenseSet<const CFGBlock *>
Visited;
512 if (std::optional<CFGStmt> cs = ri->getAs<
CFGStmt>()) {
513 const Stmt *S = cs->getStmt();
515 TF.Visit(
const_cast<Stmt *
>(S));
516 if (TF.AllValuesAreNoReturn) {
517 if (!TF.AllValuesAreNoReturn.value())
519 BlocksToCheck[B] =
true;
526 if (llvm::all_of(BlocksToCheck, BlockSatisfiesCondition))
531 if (!BlocksToCheck[B]) {
533 BlocksToCheck.erase(B);
534 for (
const auto &PredBlk : B->preds())
535 if (!BlocksToCheck.contains(PredBlk))
536 BlocksToCheck[PredBlk] = std::nullopt;
565 CFG *cfg = AC.getCFG();
574 bool AddEHEdges = AC.getAddEHEdges();
579 for (
const auto *B : *cfg) {
580 if (!live[B->getBlockID()]) {
581 if (B->preds().empty()) {
582 const Stmt *Term = B->getTerminatorStmt();
583 if (isa_and_nonnull<CXXTryStmt>(Term))
595 bool HasLiveReturn =
false;
596 bool HasFakeEdge =
false;
597 bool HasPlainEdge =
false;
598 bool HasAbnormalEdge =
false;
616 HasAbnormalEdge =
true;
625 for ( ; ri != re ; ++ri)
632 if (Term && (isa<CXXTryStmt>(Term) || isa<ObjCAtTryStmt>(Term))) {
633 HasAbnormalEdge =
true;
643 if (isa<ReturnStmt>(S) || isa<CoreturnStmt>(S)) {
644 HasLiveReturn =
true;
647 if (isa<ObjCAtThrowStmt>(S)) {
651 if (isa<CXXThrowExpr>(S)) {
655 if (isa<MSAsmStmt>(S)) {
658 HasLiveReturn =
true;
661 if (isa<CXXTryStmt>(S)) {
662 HasAbnormalEdge =
true;
666 HasAbnormalEdge =
true;
669 if (
auto *
Call = dyn_cast<CallExpr>(S)) {
670 const Expr *Callee =
Call->getCallee();
671 if (Callee->getType()->isPointerType())
673 dyn_cast<DeclRefExpr>(Callee->IgnoreParenImpCasts()))
674 if (
auto *VD = dyn_cast<VarDecl>(DeclRef->getDecl()))
676 HasAbnormalEdge =
true;
688 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
698struct CheckFallThroughDiagnostics {
699 unsigned diag_FallThrough_HasNoReturn = 0;
700 unsigned diag_FallThrough_ReturnsNonVoid = 0;
701 unsigned diag_NeverFallThroughOrReturn = 0;
705 static CheckFallThroughDiagnostics MakeForFunction(
Sema &S,
707 CheckFallThroughDiagnostics
D;
708 D.FuncLoc =
Func->getLocation();
709 D.diag_FallThrough_HasNoReturn = diag::warn_noreturn_has_return_expr;
710 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
714 bool isVirtualMethod =
false;
716 isVirtualMethod =
Method->isVirtual();
724 D.diag_FallThrough_ReturnsNonVoid = diag::ext_main_no_return;
729 D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function;
731 D.FunKind = diag::FalloffFunctionKind::Function;
735 static CheckFallThroughDiagnostics MakeForCoroutine(
const Decl *
Func) {
736 CheckFallThroughDiagnostics
D;
737 D.FuncLoc =
Func->getLocation();
738 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
739 D.FunKind = diag::FalloffFunctionKind::Coroutine;
743 static CheckFallThroughDiagnostics MakeForBlock() {
744 CheckFallThroughDiagnostics
D;
745 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;
746 D.diag_FallThrough_ReturnsNonVoid = diag::err_falloff_nonvoid;
747 D.FunKind = diag::FalloffFunctionKind::Block;
751 static CheckFallThroughDiagnostics MakeForLambda() {
752 CheckFallThroughDiagnostics
D;
753 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;
754 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
755 D.FunKind = diag::FalloffFunctionKind::Lambda;
760 bool HasNoReturn)
const {
761 if (FunKind == diag::FalloffFunctionKind::Function) {
762 return (ReturnsVoid ||
763 D.isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&
765 D.isIgnored(diag::warn_noreturn_has_return_expr, FuncLoc)) &&
767 D.isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));
769 if (FunKind == diag::FalloffFunctionKind::Coroutine) {
770 return (ReturnsVoid ||
771 D.isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&
775 return ReturnsVoid && !HasNoReturn;
787 const CheckFallThroughDiagnostics &CD,
790 bool ReturnsVoid =
false;
791 bool HasNoReturn =
false;
793 if (
const auto *FD = dyn_cast<FunctionDecl>(
D)) {
794 if (
const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
795 ReturnsVoid = CBody->getFallthroughHandler() !=
nullptr;
797 ReturnsVoid = FD->getReturnType()->isVoidType();
798 HasNoReturn = FD->isNoReturn() || FD->hasAttr<InferredNoReturnAttr>();
800 else if (
const auto *MD = dyn_cast<ObjCMethodDecl>(
D)) {
801 ReturnsVoid = MD->getReturnType()->isVoidType();
802 HasNoReturn = MD->hasAttr<NoReturnAttr>();
804 else if (isa<BlockDecl>(
D)) {
807 if (FT->getReturnType()->isVoidType())
809 if (FT->getNoReturnAttr())
817 if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
833 if (CD.diag_FallThrough_HasNoReturn)
834 S.
Diag(RBrace, CD.diag_FallThrough_HasNoReturn) << CD.FunKind;
835 }
else if (!ReturnsVoid && CD.diag_FallThrough_ReturnsNonVoid) {
839 if (
const auto *CS = dyn_cast<CompoundStmt>(Body);
840 CS && !CS->body_empty()) {
841 const Stmt *LastStmt = CS->body_back();
843 if (
const auto *EWC = dyn_cast<ExprWithCleanups>(LastStmt)) {
844 LastStmt = EWC->getSubExpr();
846 if (
const auto *CE = dyn_cast<CallExpr>(LastStmt)) {
848 Callee && Callee->hasAttr<InferredNoReturnAttr>()) {
853 if (isa<CXXThrowExpr>(LastStmt)) {
859 S.
Diag(RBrace, CD.diag_FallThrough_ReturnsNonVoid)
860 << CD.FunKind << NotInAllControlPaths;
864 if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
866 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
868 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
870 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
895 : Inherited(Context), FoundReference(
false), Needle(Needle) {}
897 void VisitExpr(
const Expr *
E) {
902 Inherited::VisitExpr(
E);
907 FoundReference =
true;
912 bool doesContainReference()
const {
return FoundReference; }
920 S.
Diag(VD->
getLocation(), diag::note_block_var_fixit_add_initialization)
949 const Stmt *Else,
bool CondVal,
973 bool IsCapturedByBlock) {
974 bool Diagnosed =
false;
1007 const Stmt *Term = I->Terminator;
1017 int RemoveDiagKind = -1;
1018 const char *FixitStr =
1019 S.
getLangOpts().CPlusPlus ? (I->Output ?
"true" :
"false")
1020 : (I->Output ?
"1" :
"0");
1023 switch (Term ? Term->
getStmtClass() : Stmt::DeclStmtClass) {
1030 case Stmt::IfStmtClass: {
1031 const IfStmt *IS = cast<IfStmt>(Term);
1037 I->Output, Fixit1, Fixit2);
1040 case Stmt::ConditionalOperatorClass: {
1047 I->Output, Fixit1, Fixit2);
1050 case Stmt::BinaryOperatorClass: {
1058 if ((BO->
getOpcode() == BO_LAnd && I->Output) ||
1059 (BO->
getOpcode() == BO_LOr && !I->Output))
1070 case Stmt::WhileStmtClass:
1073 Range = cast<WhileStmt>(Term)->getCond()->getSourceRange();
1077 case Stmt::ForStmtClass:
1080 Range = cast<ForStmt>(Term)->getCond()->getSourceRange();
1087 case Stmt::CXXForRangeStmtClass:
1088 if (I->Output == 1) {
1096 Range = cast<CXXForRangeStmt>(Term)->getRangeInit()->getSourceRange();
1100 case Stmt::DoStmtClass:
1103 Range = cast<DoStmt>(Term)->getCond()->getSourceRange();
1109 case Stmt::CaseStmtClass:
1112 Range = cast<CaseStmt>(Term)->getLHS()->getSourceRange();
1114 case Stmt::DefaultStmtClass:
1117 Range = cast<DefaultStmt>(Term)->getDefaultLoc();
1122 << VD->
getDeclName() << IsCapturedByBlock << DiagKind
1123 << Str << I->Output <<
Range;
1126 if (RemoveDiagKind != -1)
1128 << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
1162 bool alwaysReportSelfInit =
false) {
1176 if (!alwaysReportSelfInit && DRE ==
Initializer->IgnoreParenImpCasts())
1179 ContainsReference CR(S.
Context, DRE);
1181 if (CR.doesContainReference()) {
1182 S.
Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
1193 diag::warn_uninit_byref_blockvar_captured_by_block)
1213 FallthroughMapper(
Sema &S) : FoundSwitchStatements(
false), S(S) {
1214 ShouldWalkTypesOfTypeLocs =
false;
1217 bool foundSwitchStatements()
const {
return FoundSwitchStatements; }
1220 bool Found = FallthroughStmts.erase(
Stmt);
1227 const AttrStmts &getFallthroughStmts()
const {
return FallthroughStmts; }
1229 void fillReachableBlocks(
CFG *Cfg) {
1230 assert(ReachableBlocks.empty() &&
"ReachableBlocks already filled");
1231 std::deque<const CFGBlock *> BlockQueue;
1233 ReachableBlocks.insert(&Cfg->
getEntry());
1234 BlockQueue.push_back(&Cfg->
getEntry());
1239 for (
const auto *B : *Cfg) {
1240 const Stmt *L = B->getLabel();
1241 if (isa_and_nonnull<SwitchCase>(L) && ReachableBlocks.insert(B).second)
1242 BlockQueue.push_back(B);
1245 while (!BlockQueue.empty()) {
1247 BlockQueue.pop_front();
1249 if (B && ReachableBlocks.insert(B).second)
1250 BlockQueue.push_back(B);
1255 bool checkFallThroughIntoBlock(
const CFGBlock &B,
int &AnnotatedCnt,
1256 bool IsTemplateInstantiation) {
1257 assert(!ReachableBlocks.empty() &&
"ReachableBlocks empty");
1259 int UnannotatedCnt = 0;
1263 while (!BlockQueue.empty()) {
1265 BlockQueue.pop_front();
1269 const Stmt *Term =
P->getTerminatorStmt();
1270 if (isa_and_nonnull<SwitchStmt>(Term))
1273 const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(
P->getLabel());
1277 const LabelStmt *L = dyn_cast_or_null<LabelStmt>(
P->getLabel());
1281 if (!ReachableBlocks.count(
P)) {
1282 for (
const CFGElement &Elem : llvm::reverse(*
P)) {
1283 if (std::optional<CFGStmt> CS = Elem.getAs<
CFGStmt>()) {
1284 if (
const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
1288 if (!IsTemplateInstantiation)
1289 S.
Diag(AS->getBeginLoc(),
1290 diag::warn_unreachable_fallthrough_attr);
1291 markFallthroughVisited(AS);
1311 markFallthroughVisited(AS);
1318 std::copy(
P->pred_begin(),
P->pred_end(),
1319 std::back_inserter(BlockQueue));
1325 return !!UnannotatedCnt;
1329 if (asFallThroughAttr(S))
1330 FallthroughStmts.insert(S);
1334 bool VisitSwitchStmt(
SwitchStmt *S)
override {
1335 FoundSwitchStatements =
true;
1344 bool TraverseLambdaExpr(
LambdaExpr *LE)
override {
1346 for (
const auto C : zip(
LE->captures(),
LE->capture_inits()))
1354 if (
const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
1355 if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs()))
1364 for (
const CFGElement &Elem : llvm::reverse(B))
1365 if (std::optional<CFGStmt> CS = Elem.getAs<
CFGStmt>())
1366 return CS->getStmt();
1377 bool FoundSwitchStatements;
1378 AttrStmts FallthroughStmts;
1387 tok::l_square, tok::l_square,
1389 tok::r_square, tok::r_square
1395 tok::r_square, tok::r_square
1400 StringRef MacroName;
1401 if (PreferClangAttr)
1403 if (MacroName.empty())
1405 if (MacroName.empty() && !PreferClangAttr)
1407 if (MacroName.empty()) {
1408 if (!PreferClangAttr)
1409 MacroName =
"[[fallthrough]]";
1411 MacroName =
"[[clang::fallthrough]]";
1413 MacroName =
"__attribute__((fallthrough))";
1420 FallthroughMapper FM(S);
1421 FM.TraverseStmt(AC.getBody());
1423 if (!FM.foundSwitchStatements())
1426 if (PerFunction && FM.getFallthroughStmts().empty())
1429 CFG *Cfg = AC.getCFG();
1434 FM.fillReachableBlocks(Cfg);
1436 for (
const CFGBlock *B : llvm::reverse(*Cfg)) {
1439 if (!isa_and_nonnull<SwitchCase>(
Label))
1444 bool IsTemplateInstantiation =
false;
1446 IsTemplateInstantiation =
Function->isTemplateInstantiation();
1447 if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,
1448 IsTemplateInstantiation))
1452 PerFunction ? diag::warn_unannotated_fallthrough_per_function
1453 : diag::warn_unannotated_fallthrough);
1455 if (!AnnotatedCnt) {
1466 if (!(B->
empty() && isa_and_nonnull<BreakStmt>(Term))) {
1470 TextToInsert +=
"; ";
1471 S.
Diag(L, diag::note_insert_fallthrough_fixit)
1472 << AnnotationSpelling
1475 S.
Diag(L, diag::note_insert_break_fixit)
1480 for (
const auto *F : FM.getFallthroughStmts())
1481 S.
Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement);
1489 switch (S->getStmtClass()) {
1490 case Stmt::ForStmtClass:
1491 case Stmt::WhileStmtClass:
1492 case Stmt::CXXForRangeStmtClass:
1493 case Stmt::ObjCForCollectionStmtClass:
1495 case Stmt::DoStmtClass: {
1497 if (!cast<DoStmt>(S)->getCond()->
EvaluateAsInt(Result, Ctx))
1499 return Result.Val.getInt().getBoolValue();
1516 typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
1525 for (WeakObjectUseMap::const_iterator I = WeakMap.begin(),
E = WeakMap.end();
1527 const WeakUseVector &Uses = I->second;
1530 WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
1531 for ( ; UI != UE; ++UI) {
1544 if (UI == Uses.begin()) {
1545 WeakUseVector::const_iterator UI2 = UI;
1546 for (++UI2; UI2 != UE; ++UI2)
1547 if (UI2->isUnsafe())
1551 if (!
isInLoop(Ctx, PM, UI->getUseExpr()))
1554 const WeakObjectProfileTy &Profile = I->first;
1555 if (!Profile.isExactProfile())
1560 Base = Profile.getProperty();
1561 assert(
Base &&
"A profile always has a base or property.");
1563 if (
const VarDecl *BaseVar = dyn_cast<VarDecl>(
Base))
1564 if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(
Base))
1569 UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
1572 if (UsesByStmt.empty())
1577 llvm::sort(UsesByStmt,
1578 [&
SM](
const StmtUsesPair &LHS,
const StmtUsesPair &RHS) {
1580 RHS.first->getBeginLoc());
1595 if (isa<sema::BlockScopeInfo>(CurFn))
1596 FunctionKind =
Block;
1597 else if (isa<sema::LambdaScopeInfo>(CurFn))
1598 FunctionKind = Lambda;
1599 else if (isa<ObjCMethodDecl>(
D))
1605 for (
const auto &
P : UsesByStmt) {
1606 const Stmt *FirstRead =
P.first;
1607 const WeakObjectProfileTy &Key =
P.second->first;
1608 const WeakUseVector &Uses =
P.second->second;
1616 if (Key.isExactProfile())
1617 DiagKind = diag::warn_arc_repeated_use_of_weak;
1619 DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
1631 const NamedDecl *KeyProp = Key.getProperty();
1632 if (isa<VarDecl>(KeyProp))
1634 else if (isa<ObjCPropertyDecl>(KeyProp))
1636 else if (isa<ObjCMethodDecl>(KeyProp))
1637 ObjectKind = ImplicitProperty;
1638 else if (isa<ObjCIvarDecl>(KeyProp))
1641 llvm_unreachable(
"Unexpected weak object kind!");
1646 if (Prop->hasAttr<IBOutletAttr>())
1651 <<
int(ObjectKind) << KeyProp <<
int(FunctionKind)
1655 for (
const auto &Use : Uses) {
1656 if (Use.getUseExpr() == FirstRead)
1658 S.
Diag(Use.getUseExpr()->getBeginLoc(),
1659 diag::note_arc_weak_also_accessed_here)
1660 << Use.getUseExpr()->getSourceRange();
1668typedef std::pair<PartialDiagnosticAt, OptionalNotes>
DelayedDiag;
1669typedef std::list<DelayedDiag>
DiagList;
1671struct SortDiagBySourceLocation {
1675 bool operator()(
const DelayedDiag &left,
const DelayedDiag &right) {
1678 return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
1688 typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
1692 typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
1696 UninitValsDiagReporter(
Sema &S) : S(S) {}
1699 MappedType &getUses(
const VarDecl *vd) {
1700 MappedType &
V = uses[vd];
1701 if (!
V.getPointer())
1702 V.setPointer(
new UsesVec());
1708 getUses(vd).getPointer()->push_back(use);
1714 for (
const auto &
P : uses) {
1716 const MappedType &
V =
P.second;
1718 UsesVec *vec =
V.getPointer();
1719 bool hasSelfInit =
V.getInt();
1721 diagnoseUnitializedVar(vd, hasSelfInit, vec);
1731 static bool hasAlwaysUninitializedUse(
const UsesVec* vec) {
1732 return llvm::any_of(*vec, [](
const UninitUse &
U) {
1742 void diagnoseUnitializedVar(
const VarDecl *vd,
bool hasSelfInit,
1747 if (hasSelfInit && hasAlwaysUninitializedUse(vec)) {
1762 return b.isConstRefOrPtrUse();
1769 for (
const auto &
U : *vec) {
1770 if (
U.isConstRefUse()) {
1773 }
else if (
U.isConstPtrUse()) {
1787class CalledOnceInterProceduralData {
1792 DelayedBlockWarnings[
Block].emplace_back(std::move(
Warning));
1797 S.
Diag(Delayed.first, Delayed.second);
1799 discardWarnings(
Block);
1803 DelayedBlockWarnings.erase(
Block);
1808 llvm::DenseMap<const BlockDecl *, DelayedDiagnostics> DelayedBlockWarnings;
1813 CalledOnceCheckReporter(
Sema &S, CalledOnceInterProceduralData &Data)
1816 const Expr *PrevCall,
bool IsCompletionHandler,
1817 bool Poised)
override {
1818 auto DiagToReport = IsCompletionHandler
1819 ? diag::warn_completion_handler_called_twice
1820 : diag::warn_called_once_gets_called_twice;
1822 S.
Diag(PrevCall->
getBeginLoc(), diag::note_called_once_gets_called_twice)
1827 bool IsCompletionHandler)
override {
1828 auto DiagToReport = IsCompletionHandler
1829 ? diag::warn_completion_handler_never_called
1830 : diag::warn_called_once_never_called;
1837 bool IsCalledDirectly,
1838 bool IsCompletionHandler)
override {
1839 auto DiagToReport = IsCompletionHandler
1840 ? diag::warn_completion_handler_never_called_when
1841 : diag::warn_called_once_never_called_when;
1845 << (
unsigned)Reason);
1847 if (
const auto *
Block = dyn_cast<BlockDecl>(Function)) {
1857 bool IsCompletionHandler)
override {
1858 auto DiagToReport = IsCompletionHandler
1859 ? diag::warn_completion_handler_never_called
1860 : diag::warn_called_once_never_called;
1876 CalledOnceInterProceduralData &
Data;
1879constexpr unsigned CalledOnceWarnings[] = {
1880 diag::warn_called_once_never_called,
1881 diag::warn_called_once_never_called_when,
1882 diag::warn_called_once_gets_called_twice};
1884constexpr unsigned CompletionHandlerWarnings[]{
1885 diag::warn_completion_handler_never_called,
1886 diag::warn_completion_handler_never_called_when,
1887 diag::warn_completion_handler_called_twice};
1892 return llvm::any_of(DiagIDs, [&Diags, At](
unsigned DiagID) {
1899 return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);
1904 return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||
1905 shouldAnalyzeCalledOnceConventions(Diags, At);
1913namespace threadSafety {
1924 if (Verbose && CurrentFunction) {
1926 S.
PDiag(diag::note_thread_warning_in_fun)
1927 << CurrentFunction);
1935 if (Verbose && CurrentFunction) {
1937 S.
PDiag(diag::note_thread_warning_in_fun)
1938 << CurrentFunction);
1939 ONS.push_back(std::move(FNote));
1947 ONS.push_back(Note1);
1948 ONS.push_back(Note2);
1949 if (Verbose && CurrentFunction) {
1951 S.
PDiag(diag::note_thread_warning_in_fun)
1952 << CurrentFunction);
1953 ONS.push_back(std::move(FNote));
1961 LocLocked, S.
PDiag(diag::note_locked_here) << Kind))
1969 LocUnlocked, S.
PDiag(diag::note_unlocked_here) << Kind))
1977 S.
PDiag(diag::note_managed_mismatch_here_for_param)))
1983 : S(S), FunLocation(FL), FunEndLocation(FEL),
1984 CurrentFunction(nullptr), Verbose(
false) {}
1986 void setVerbose(
bool b) { Verbose =
b; }
1994 for (
const auto &
Diag : Warnings) {
1996 for (
const auto &
Note :
Diag.second)
2002 Name scopeName, StringRef Kind,
2003 Name expected, Name actual)
override {
2005 S.
PDiag(diag::warn_unmatched_underlying_mutexes)
2006 << Kind << scopeName << expected << actual);
2007 Warnings.emplace_back(std::move(
Warning),
2008 makeManagedMismatchNoteForParam(DLoc));
2014 Name expected)
override {
2016 Loc, S.
PDiag(diag::warn_expect_more_underlying_mutexes)
2017 << Kind << scopeName << expected);
2018 Warnings.emplace_back(std::move(
Warning),
2019 makeManagedMismatchNoteForParam(DLoc));
2025 Name actual)
override {
2027 Loc, S.
PDiag(diag::warn_expect_fewer_underlying_mutexes)
2028 << Kind << scopeName << actual);
2029 Warnings.emplace_back(std::move(
Warning),
2030 makeManagedMismatchNoteForParam(DLoc));
2036 Warnings.emplace_back(std::move(
Warning), getNotes());
2044 << Kind << LockName);
2045 Warnings.emplace_back(std::move(
Warning),
2046 makeUnlockedHereNote(LocPreviousUnlock, Kind));
2049 void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
2054 LocUnlock = FunLocation;
2056 LocUnlock, S.
PDiag(diag::warn_unlock_kind_mismatch)
2057 << Kind << LockName << Received <<
Expected);
2058 Warnings.emplace_back(std::move(
Warning),
2059 makeLockedHereNote(LocLocked, Kind));
2062 void handleDoubleLock(StringRef Kind, Name LockName,
SourceLocation LocLocked,
2065 LocDoubleLock = FunLocation;
2067 << Kind << LockName);
2068 Warnings.emplace_back(std::move(
Warning),
2069 makeLockedHereNote(LocLocked, Kind));
2072 void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
2076 bool ReentrancyMismatch)
override {
2077 unsigned DiagID = 0;
2080 DiagID = diag::warn_lock_some_predecessors;
2083 DiagID = diag::warn_expecting_lock_held_on_loop;
2086 DiagID = diag::warn_no_unlock;
2089 DiagID = diag::warn_expecting_locked;
2093 LocEndOfScope = FunEndLocation;
2097 << ReentrancyMismatch);
2098 Warnings.emplace_back(std::move(
Warning),
2099 makeLockedHereNote(LocLocked, Kind));
2102 void handleExclusiveAndShared(StringRef Kind, Name LockName,
2106 S.
PDiag(diag::warn_lock_exclusive_and_shared)
2107 << Kind << LockName);
2109 << Kind << LockName);
2110 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2115 unsigned DiagID = 0;
2122 DiagID = diag::warn_variable_requires_any_lock;
2129 DiagID = diag::warn_var_deref_requires_any_lock;
2132 llvm_unreachable(
"Only works for variables");
2137 Warnings.emplace_back(std::move(
Warning), getNotes());
2140 void handleMutexNotHeld(StringRef Kind,
const NamedDecl *
D,
2143 Name *PossibleMatch)
override {
2144 unsigned DiagID = 0;
2145 if (PossibleMatch) {
2148 DiagID = diag::warn_variable_requires_lock_precise;
2151 DiagID = diag::warn_var_deref_requires_lock_precise;
2154 DiagID = diag::warn_fun_requires_lock_precise;
2157 DiagID = diag::warn_guarded_pass_by_reference;
2160 DiagID = diag::warn_pt_guarded_pass_by_reference;
2163 DiagID = diag::warn_guarded_return_by_reference;
2166 DiagID = diag::warn_pt_guarded_return_by_reference;
2169 DiagID = diag::warn_guarded_pass_pointer;
2172 DiagID = diag::warn_pt_guarded_pass_pointer;
2175 DiagID = diag::warn_guarded_return_pointer;
2178 DiagID = diag::warn_pt_guarded_return_pointer;
2188 S.
PDiag(diag::note_guarded_by_declared_here)
2189 <<
D->getDeclName());
2190 Warnings.emplace_back(std::move(
Warning), getNotes(
Note, VNote));
2192 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2196 DiagID = diag::warn_variable_requires_lock;
2199 DiagID = diag::warn_var_deref_requires_lock;
2202 DiagID = diag::warn_fun_requires_lock;
2205 DiagID = diag::warn_guarded_pass_by_reference;
2208 DiagID = diag::warn_pt_guarded_pass_by_reference;
2211 DiagID = diag::warn_guarded_return_by_reference;
2214 DiagID = diag::warn_pt_guarded_return_by_reference;
2217 DiagID = diag::warn_guarded_pass_pointer;
2220 DiagID = diag::warn_pt_guarded_pass_pointer;
2223 DiagID = diag::warn_guarded_return_pointer;
2226 DiagID = diag::warn_pt_guarded_return_pointer;
2234 S.
PDiag(diag::note_guarded_by_declared_here));
2235 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2237 Warnings.emplace_back(std::move(
Warning), getNotes());
2241 void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
2244 S.
PDiag(diag::warn_acquire_requires_negative_cap)
2245 << Kind << LockName << Neg);
2246 Warnings.emplace_back(std::move(
Warning), getNotes());
2249 void handleNegativeNotHeld(
const NamedDecl *
D, Name LockName,
2252 Loc, S.
PDiag(diag::warn_fun_requires_negative_cap) <<
D << LockName);
2253 Warnings.emplace_back(std::move(
Warning), getNotes());
2256 void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
2259 << Kind << FunName << LockName);
2260 Warnings.emplace_back(std::move(
Warning), getNotes());
2263 void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
2266 S.
PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
2267 Warnings.emplace_back(std::move(
Warning), getNotes());
2272 S.
PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
2273 Warnings.emplace_back(std::move(
Warning), getNotes());
2277 CurrentFunction = FD;
2281 CurrentFunction =
nullptr;
2295class ConsumedWarningsHandler :
public ConsumedWarningsHandlerBase {
2302 ConsumedWarningsHandler(
Sema &S) : S(S) {}
2306 for (
const auto &
Diag : Warnings) {
2308 for (
const auto &
Note :
Diag.second)
2314 StringRef VariableName)
override {
2322 StringRef VariableName,
2323 StringRef ExpectedState,
2324 StringRef ObservedState)
override {
2327 diag::warn_param_return_typestate_mismatch) << VariableName <<
2328 ExpectedState << ObservedState);
2334 StringRef ObservedState)
override {
2337 diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
2343 StringRef TypeName)
override {
2345 diag::warn_return_typestate_for_unconsumable_type) << TypeName);
2351 StringRef ObservedState)
override {
2354 diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
2359 void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
2363 diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
2368 void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
2372 MethodName << VariableName << State);
2388 bool SuggestSuggestions;
2392 std::string listVariableGroupAsString(
2394 if (VarGroupForVD.size() <= 1)
2397 std::vector<StringRef> VarNames;
2398 auto PutInQuotes = [](StringRef S) -> std::string {
2399 return "'" + S.str() +
"'";
2402 for (
auto *
V : VarGroupForVD) {
2405 VarNames.push_back(
V->getName());
2407 if (VarNames.size() == 1) {
2408 return PutInQuotes(VarNames[0]);
2410 if (VarNames.size() == 2) {
2411 return PutInQuotes(VarNames[0]) +
" and " + PutInQuotes(VarNames[1]);
2413 assert(VarGroupForVD.size() > 3);
2414 const unsigned N = VarNames.size() -
2416 std::string AllVars =
"";
2418 for (
unsigned I = 0; I < N; ++I)
2419 AllVars.append(PutInQuotes(VarNames[I]) +
", ");
2420 AllVars.append(PutInQuotes(VarNames[N]) +
", and " +
2421 PutInQuotes(VarNames[N + 1]));
2426 UnsafeBufferUsageReporter(
Sema &S,
bool SuggestSuggestions)
2427 : S(S), SuggestSuggestions(SuggestSuggestions) {}
2433 unsigned MsgParam = 0;
2435 if (
const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
2436 Loc = ASE->getBase()->getExprLoc();
2437 Range = ASE->getBase()->getSourceRange();
2439 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
2441 if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
2442 Op == BO_SubAssign) {
2452 }
else if (
const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
2454 if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
2461 if (isa<CallExpr>(Operation) || isa<CXXConstructExpr>(Operation)) {
2463 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2465 }
else if (isa<MemberExpr>(Operation)) {
2467 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2468 auto *ME = cast<MemberExpr>(Operation);
2469 D = ME->getMemberDecl();
2471 }
else if (
const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) {
2472 QualType destType = ECE->getType();
2473 bool destTypeComplete =
true;
2475 if (!isa<PointerType>(destType))
2479 destTypeComplete =
D->isCompleteDefinition();
2483 if (destTypeComplete) {
2485 QualType srcType = ECE->getSubExpr()->getType();
2495 if (
const auto *CE = dyn_cast<CXXMemberCallExpr>(
2496 ECE->getSubExpr()->IgnoreParens())) {
2497 D = CE->getMethodDecl();
2508 if (IsRelatedToDecl) {
2509 assert(!SuggestSuggestions &&
2510 "Variables blamed for unsafe buffer usage without suggestions!");
2511 S.
Diag(
Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2514 S.
Diag(
Loc, diag::warn_unsafe_buffer_operation)
2515 << MsgParam <<
D <<
Range;
2517 S.
Diag(
Loc, diag::warn_unsafe_buffer_operation) << MsgParam <<
Range;
2519 if (SuggestSuggestions) {
2520 S.
Diag(
Loc, diag::note_safe_buffer_usage_suggestions_disabled);
2527 const Expr *UnsafeArg =
nullptr)
override {
2528 S.
Diag(
Call->getBeginLoc(), diag::warn_unsafe_buffer_libc_call)
2529 <<
Call->getDirectCallee()
2530 <<
Call->getSourceRange();
2531 if (PrintfInfo > 0) {
2533 UnsafeArg ? UnsafeArg->getSourceRange() :
Call->getSourceRange();
2534 S.
Diag(R.
getBegin(), diag::note_unsafe_buffer_printf_call)
2540 bool IsRelatedToDecl,
2544 unsigned MsgParam = 0;
2548 const auto *CtorExpr = cast<CXXConstructExpr>(Operation);
2549 Loc = CtorExpr->getLocation();
2551 S.
Diag(
Loc, diag::warn_unsafe_buffer_usage_in_container);
2552 if (IsRelatedToDecl) {
2553 assert(!SuggestSuggestions &&
2554 "Variables blamed for unsafe buffer usage without suggestions!");
2555 S.
Diag(
Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2561 FixItList &&Fixes,
const Decl *
D,
2563 assert(!SuggestSuggestions &&
2564 "Unsafe buffer usage fixits displayed without suggestions!");
2568 if (!Fixes.empty()) {
2569 assert(isa<NamedDecl>(
D) &&
2570 "Fix-its are generated only for `NamedDecl`s");
2572 bool BriefMsg =
false;
2577 unsigned FixItStrategy = 0;
2586 assert(
false &&
"We support only std::span and std::array");
2591 BriefMsg ? diag::note_unsafe_buffer_variable_fixit_together
2592 : diag::note_unsafe_buffer_variable_fixit_group);
2595 FD << listVariableGroupAsString(
Variable, VarGroupForVD)
2596 << (VarGroupForVD.size() > 1) << ND;
2597 for (
const auto &F : Fixes) {
2605 S.
Diag(
Note.first, diag::note_safe_buffer_debug_mode) <<
Note.second;
2626 StringRef WSSuffix =
"")
const override {
2628 TokenValue ClangUnsafeBufferUsageTokens[] = {
2637 StringRef MacroName;
2641 if (MacroName.empty())
2642 MacroName =
"[[clang::unsafe_buffer_usage]]";
2643 return MacroName.str() + WSSuffix.str();
2654 enableCheckFallThrough = 1;
2655 enableCheckUnreachable = 0;
2656 enableThreadSafetyAnalysis = 0;
2657 enableConsumedAnalysis = 0;
2678template <
typename... Ts>
2681 return (!
D.isIgnored(Diags,
Loc) || ...);
2686 NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),
2687 MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),
2688 NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
2689 NumUninitAnalysisBlockVisits(0),
2690 MaxUninitAnalysisBlockVisitsPerFunction(0) {
2698 using namespace diag;
2704 P.enableCheckUnreachable =
2705 PolicyOverrides.enableCheckUnreachable ||
2707 warn_unreachable_return, warn_unreachable_loop_increment);
2709 P.enableThreadSafetyAnalysis = PolicyOverrides.enableThreadSafetyAnalysis ||
2712 P.enableConsumedAnalysis = PolicyOverrides.enableConsumedAnalysis ||
2717void sema::AnalysisBasedWarnings::clearOverrides() {
2718 PolicyOverrides.enableCheckUnreachable =
false;
2719 PolicyOverrides.enableConsumedAnalysis =
false;
2720 PolicyOverrides.enableThreadSafetyAnalysis =
false;
2732 llvm::function_ref<void(
const Decl *)> Callback;
2733 const Module *
const TUModule;
2737 const Module *
const TUModule)
2738 : Callback(Callback), TUModule(TUModule) {
2739 ShouldVisitTemplateInstantiations =
true;
2740 ShouldVisitImplicitCode =
false;
2747 if (
Node &&
Node->getOwningModule() == TUModule)
2753 if (cast<DeclContext>(
Node)->isDependentContext())
2758 if (
Node->doesThisDeclarationHaveABody())
2764 if (cast<DeclContext>(
Node)->isDependentContext())
2771 if (cast<DeclContext>(
Node)->isDependentContext())
2773 if (
Node->hasBody())
2779 return VisitFunctionDecl(
Node->getCallOperator());
2785class LifetimeSafetyReporterImpl :
public LifetimeSafetyReporter {
2788 LifetimeSafetyReporterImpl(
Sema &S) : S(S) {}
2790 void reportUseAfterFree(
const Expr *IssueExpr,
const Expr *UseExpr,
2793 C == Confidence::Definite
2794 ? diag::warn_lifetime_safety_loan_expires_permissive
2795 : diag::warn_lifetime_safety_loan_expires_strict)
2797 S.
Diag(FreeLoc, diag::note_lifetime_safety_destroyed_here);
2798 S.
Diag(UseExpr->
getExprLoc(), diag::note_lifetime_safety_used_here)
2822 bool UnsafeBufferUsageCanEmitSuggestions = S.
getLangOpts().CPlusPlus20;
2823 bool UnsafeBufferUsageShouldEmitSuggestions =
2824 UnsafeBufferUsageCanEmitSuggestions &&
2825 DiagOpts.ShowSafeBufferUsageSuggestions;
2826 bool UnsafeBufferUsageShouldSuggestSuggestions =
2827 UnsafeBufferUsageCanEmitSuggestions &&
2828 !DiagOpts.ShowSafeBufferUsageSuggestions;
2829 UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions);
2832 auto CallAnalyzers = [&](
const Decl *
Node) ->
void {
2833 if (
Node->hasAttr<UnsafeBufferUsageAttr>())
2837 if (!Diags.
isIgnored(diag::warn_unsafe_buffer_operation,
2838 Node->getBeginLoc()) ||
2839 !Diags.
isIgnored(diag::warn_unsafe_buffer_variable,
2840 Node->getBeginLoc()) ||
2841 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2842 Node->getBeginLoc()) ||
2843 !Diags.
isIgnored(diag::warn_unsafe_buffer_libc_call,
2844 Node->getBeginLoc())) {
2846 UnsafeBufferUsageShouldEmitSuggestions);
2855 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2860 .TraverseTranslationUnitDecl(TU);
2883 if (cast<DeclContext>(
D)->isDependentContext())
2900 AC.getCFGBuildOptions().PruneTriviallyFalseEdges =
true;
2901 AC.getCFGBuildOptions().AddEHEdges =
false;
2902 AC.getCFGBuildOptions().AddInitializers =
true;
2903 AC.getCFGBuildOptions().AddImplicitDtors =
true;
2904 AC.getCFGBuildOptions().AddTemporaryDtors =
true;
2905 AC.getCFGBuildOptions().AddCXXNewAllocator =
false;
2906 AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors =
true;
2914 if (
P.enableCheckUnreachable ||
P.enableThreadSafetyAnalysis ||
2915 P.enableConsumedAnalysis) {
2917 AC.getCFGBuildOptions().setAllAlwaysAdd();
2920 AC.getCFGBuildOptions()
2921 .setAlwaysAdd(Stmt::BinaryOperatorClass)
2922 .setAlwaysAdd(Stmt::CompoundAssignOperatorClass)
2923 .setAlwaysAdd(Stmt::BlockExprClass)
2924 .setAlwaysAdd(Stmt::CStyleCastExprClass)
2925 .setAlwaysAdd(Stmt::DeclRefExprClass)
2926 .setAlwaysAdd(Stmt::ImplicitCastExprClass)
2927 .setAlwaysAdd(Stmt::UnaryOperatorClass);
2930 bool EnableLifetimeSafetyAnalysis = S.
getLangOpts().EnableLifetimeSafety;
2932 std::optional<LogicalErrorHandler> LEH;
2933 if (LogicalErrorHandler::hasActiveDiagnostics(Diags,
D->
getBeginLoc())) {
2935 AC.getCFGBuildOptions().Observer = &*LEH;
2940 bool analyzed =
false;
2944 for (
const Stmt *S :
D.Stmts)
2945 AC.registerForcedBlockExpression(S);
2951 bool AllReachable =
true;
2952 for (
const Stmt *S :
D.Stmts) {
2953 const CFGBlock *block = AC.getBlockForRegisteredExpression(S);
2955 AC.getCFGReachablityAnalysis();
2961 if (!cra->
isReachable(&AC.getCFG()->getEntry(), block)) {
2962 AllReachable =
false;
2980 if (
P.enableCheckFallThrough) {
2981 const CheckFallThroughDiagnostics &CD =
2982 (isa<BlockDecl>(
D) ? CheckFallThroughDiagnostics::MakeForBlock()
2983 : (isa<CXXMethodDecl>(
D) &&
2984 cast<CXXMethodDecl>(
D)->getOverloadedOperator() == OO_Call &&
2985 cast<CXXMethodDecl>(
D)->getParent()->isLambda())
2986 ? CheckFallThroughDiagnostics::MakeForLambda()
2988 ? CheckFallThroughDiagnostics::MakeForCoroutine(
D)
2989 : CheckFallThroughDiagnostics::MakeForFunction(S,
D)));
2994 if (
P.enableCheckUnreachable) {
3007 if (
P.enableThreadSafetyAnalysis) {
3010 threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
3012 Reporter.setIssueBetaWarnings(
true);
3014 Reporter.setVerbose(
true);
3018 Reporter.emitDiagnostics();
3022 if (
P.enableConsumedAnalysis) {
3023 consumed::ConsumedWarningsHandler WarningHandler(S);
3033 if (
CFG *cfg = AC.getCFG()) {
3034 UninitValsDiagReporter reporter(S);
3041 ++NumUninitAnalysisFunctions;
3044 MaxUninitAnalysisVariablesPerFunction =
3045 std::max(MaxUninitAnalysisVariablesPerFunction,
3047 MaxUninitAnalysisBlockVisitsPerFunction =
3048 std::max(MaxUninitAnalysisBlockVisitsPerFunction,
3056 if (EnableLifetimeSafetyAnalysis && S.
getLangOpts().CPlusPlus) {
3058 lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);
3064 shouldAnalyzeCalledOnceParameters(Diags,
D->
getBeginLoc())) {
3066 CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);
3069 shouldAnalyzeCalledOnceConventions(Diags,
D->
getBeginLoc()));
3073 bool FallThroughDiagFull =
3075 bool FallThroughDiagPerFunction = !Diags.
isIgnored(
3076 diag::warn_unannotated_fallthrough_per_function,
D->
getBeginLoc());
3077 if (FallThroughDiagFull || FallThroughDiagPerFunction ||
3088 if (!Diags.
isIgnored(diag::warn_infinite_recursive_function,
3103 if (LogicalErrorHandler::hasActiveDiagnostics(Diags,
D->
getBeginLoc())) {
3112 ++NumFunctionsAnalyzed;
3113 if (
CFG *cfg = AC.getCFG()) {
3116 NumCFGBlocks += cfg->getNumBlockIDs();
3117 MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
3118 cfg->getNumBlockIDs());
3120 ++NumFunctionsWithBadCFGs;
3126 llvm::errs() <<
"\n*** Analysis Based Warnings Stats:\n";
3128 unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
3129 unsigned AvgCFGBlocksPerFunction =
3130 !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
3131 llvm::errs() << NumFunctionsAnalyzed <<
" functions analyzed ("
3132 << NumFunctionsWithBadCFGs <<
" w/o CFGs).\n"
3133 <<
" " << NumCFGBlocks <<
" CFG blocks built.\n"
3134 <<
" " << AvgCFGBlocksPerFunction
3135 <<
" average CFG blocks per function.\n"
3136 <<
" " << MaxCFGBlocksPerFunction
3137 <<
" max CFG blocks per function.\n";
3139 unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
3140 : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
3141 unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
3142 : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
3143 llvm::errs() << NumUninitAnalysisFunctions
3144 <<
" functions analyzed for uninitialiazed variables\n"
3145 <<
" " << NumUninitAnalysisVariables <<
" variables analyzed.\n"
3146 <<
" " << AvgUninitVariablesPerFunction
3147 <<
" average variables per function.\n"
3148 <<
" " << MaxUninitAnalysisVariablesPerFunction
3149 <<
" max variables per function.\n"
3150 <<
" " << NumUninitAnalysisBlockVisits <<
" block visits.\n"
3151 <<
" " << AvgUninitBlockVisitsPerFunction
3152 <<
" average block visits per function.\n"
3153 <<
" " << MaxUninitAnalysisBlockVisitsPerFunction
3154 <<
" 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 isReferenceToNoReturn(const Expr *E)
Checks if the given expression is a reference to a function with 'noreturn' attribute.
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 CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, QualType BlockType, const CheckFallThroughDiagnostics &CD, AnalysisDeclContext &AC)
CheckFallThroughForBody - Check that we don't fall off the end of a function that should return a val...
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 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 areAnyEnabled(DiagnosticsEngine &D, SourceLocation Loc, Ts... Diags)
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 areAllValuesNoReturn(const VarDecl *VD, const CFGBlock &VarBlk, AnalysisDeclContext &AC)
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 bool DiagnoseUninitializedConstPtrUse(Sema &S, const VarDecl *VD, const UninitUse &Use)
Diagnose uninitialized const pointer usages.
static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC)
CheckUnreachable - Check for unreachable code.
@ NeverFallThroughOrReturn
static bool isInitializedWithNoReturn(const VarDecl *VD)
Checks if the given variable, which is assumed to be a function pointer, is initialized with a functi...
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)
llvm::DenseMap< Stmt *, Stmt * > MapTy
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, const Module *const TUModule)
bool VisitObjCMethodDecl(ObjCMethodDecl *Node) override
bool TraverseDecl(Decl *Node) override
bool VisitBlockDecl(BlockDecl *Node) override
bool VisitFunctionDecl(FunctionDecl *Node) override
bool VisitLambdaExpr(LambdaExpr *Node) override
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
AnalysisDeclContext contains the context data for the function, method or block under analysis.
Represents an attribute applied to a statement.
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isLogicalOp(Opcode Opc)
SourceLocation getBeginLoc() const LLVM_READONLY
SourceLocation getOperatorLoc() const
SourceLocation getExprLoc() const
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
Represents a block literal declaration, which is like an unnamed FunctionDecl.
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
SourceLocation getBeginLoc() const LLVM_READONLY
unsigned IgnoreDefaultsWithCoveredEnums
Represents a single basic block in a source-level CFG.
filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const
reverse_iterator rbegin()
bool hasNoReturnElement() const
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
pred_iterator pred_begin()
unsigned getBlockID() const
unsigned succ_size() const
CFGCallback defines methods that should be called when a logical operator error is found when buildin...
virtual void compareBitwiseEquality(const BinaryOperator *B, bool isAlwaysTrue)
virtual void logicAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue)
virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue)
virtual void compareBitwiseOr(const BinaryOperator *B)
Represents a top-level expression in a basic block.
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type.
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
bool isReachable(const CFGBlock *Src, const CFGBlock *Dst)
Returns true if the block 'Dst' can be reached from block 'Src'.
const Stmt * getStmt() const
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Represents a call to a member function that may be written either with member call syntax (e....
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
Represents a static or instance method of a struct/union/class.
A C++ throw-expression (C++ [except.throw]).
SourceLocation getThrowLoc() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
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.
void enqueueBlock(const CFGBlock *Block)
const CFGBlock * dequeue()
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
bool isFunctionOrMethod() const
A reference to a declared variable, function, enum, etc.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
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...
Module * getOwningModule() const
Get the module that owns this declaration (for visibility purposes).
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
SourceLocation getLocation() const
DeclContext * getDeclContext()
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 isLastDiagnosticIgnored() const
Determine whether the previous diagnostic was ignored.
bool getIgnoreAllWarnings() const
DiagnosticOptions & getDiagnosticOptions() const
Retrieve the diagnostic options.
bool isIgnored(unsigned DiagID, SourceLocation Loc) const
Determine whether the diagnostic is known to be ignored.
bool getSuppressSystemWarnings() const
Recursive AST visitor that supports extension via dynamic dispatch.
virtual bool TraverseDecl(MaybeConst< Decl > *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
virtual bool TraverseLambdaCapture(MaybeConst< LambdaExpr > *LE, const LambdaCapture *C, MaybeConst< Expr > *Init)
Recursively visit a lambda capture.
void VisitDeclRefExpr(PTR(DeclRefExpr) E)
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
static FixItHint CreateRemoval(CharSourceRange RemoveRange)
Create a code modification hint that removes the given source range.
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
Kind lookup(const VarDecl *VD) const
Represents a function declaration or definition.
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
FunctionDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
SourceRange getExceptionSpecSourceRange() const
Attempt to compute an informative source range covering the function exception specification,...
@ TK_MemberSpecialization
TemplatedKind getTemplatedKind() const
What kind of templated function this is.
bool isCPUDispatchMultiVersion() const
True if this function is a multiversioned dispatch function as a part of the cpu_specific/cpu_dispatc...
Represents a prototype with parameter type info, e.g.
FunctionType - C99 6.7.5.3 - Function Declarators.
IfStmt - This represents an if/then/else.
LabelStmt - Represents a label, which has a substatement.
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
Describes a module or submodule.
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>::".
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.
bool isConstant(const ASTContext &Ctx) const
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
QualType getCanonicalType() const
bool isConstQualified() const
Determine whether this type is const-qualified.
bool hasObjCLifetime() const
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
PartialDiagnostic PDiag(unsigned DiagID=0)
Build a partial diagnostic.
Sema - This implements semantic analysis and AST building for C.
Preprocessor & getPreprocessor() const
DiagnosticsEngine & getDiagnostics() const
ASTContext & getASTContext() const
std::string getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const
Get a string to suggest for zero-initialization of a type.
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Calls Lexer::getLocForEndOfToken()
const LangOptions & getLangOpts() const
threadSafety::BeforeSet * ThreadSafetyDeclCache
bool CollectStats
Flag indicating whether or not to collect detailed statistics.
SourceManager & getSourceManager() const
bool handlerCanCatch(QualType HandlerType, QualType ExceptionType)
bool hasUncompilableErrorOccurred() const
Whether uncompilable error has occurred.
SourceManager & SourceMgr
DiagnosticsEngine & Diags
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
bool isInMainFile(SourceLocation Loc) const
Returns whether the PresumedLoc for a given SourceLocation is in the main file.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
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
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
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.
TagDecl * getAsTagDecl() const
Retrieves the TagDecl that this type refers to, either because the type is a TagType or because it is...
const T * getAs() const
Member-template getAs<specific type>'.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
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
bool isConstRefOrPtrUse() 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'.
The interface that lets the caller handle unsafe buffer usage analysis results by overriding this cla...
bool areDebugNotesRequested()
virtual std::string getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, StringRef WSSuffix="") const =0
virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const =0
virtual bool ignoreUnsafeBufferInContainer(const SourceLocation &Loc) const =0
virtual void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation over raw pointers is found.
virtual void handleUnsafeVariableGroup(const VarDecl *Variable, const VariableGroupsManager &VarGrpMgr, FixItList &&Fixes, const Decl *D, const FixitStrategy &VarTargetTypes)=0
Invoked when a fix is suggested against a variable.
virtual void handleUnsafeOperationInContainer(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation with a std container is found.
virtual bool ignoreUnsafeBufferInLibcCall(const SourceLocation &Loc) const =0
virtual void handleUnsafeLibcCall(const CallExpr *Call, unsigned PrintfInfo, ASTContext &Ctx, const Expr *UnsafeArg=nullptr)=0
Invoked when a call to an unsafe libc function is found.
Represents a variable declaration or definition.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
VarDecl * getDefinition(ASTContext &)
Get the real (not just tentative) definition for this declaration.
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)
Policy getPolicyInEffectAt(SourceLocation Loc)
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.
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 runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter)
The main entry point for the analysis.
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.
LockErrorKind
This enum distinguishes between different situations where we warn due to inconsistent locking.
@ LEK_NotLockedAtEndOfFunction
Expecting a capability to be held at the end of function.
@ LEK_LockedSomePredecessors
A capability is locked in some but not all predecessors of a CFGBlock.
@ LEK_LockedAtEndOfFunction
A capability is still locked at the end of a function.
@ LEK_LockedSomeLoopIterations
A capability is locked for some but not all loop iterations.
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_PassPointer
Passing pointer to a guarded variable.
@ 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_PtPassPointer
Passing a pt-guarded pointer.
@ POK_PtReturnPointer
Returning a pt-guarded pointer.
@ POK_VarAccess
Reading or writing a variable (e.g. x in x = 5;)
@ POK_FunctionCall
Making a function call (e.g. fool())
@ POK_ReturnPointer
Returning pointer to a guarded variable.
@ POK_PtReturnByRef
Returning a pt-guarded variable by reference.
The JSON file list parser is used to communicate input to InstallAPI.
bool isTemplateInstantiation(TemplateSpecializationKind Kind)
Determine whether this template specialization kind refers to an instantiation of an entity (as oppos...
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
@ If
'if' clause, allowed on all the Compute Constructs, Data Constructs, Executable Constructs,...
@ Property
The type of a property.
@ Parameter
The parameter type of a method or function.
void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats)
void checkCalledOnceParameters(AnalysisDeclContext &AC, CalledOnceCheckHandler &Handler, bool CheckConventionalParameters)
Check given CFG for 'called once' parameter violations.
std::pair< SourceLocation, PartialDiagnostic > PartialDiagnosticAt
A partial diagnostic along with the source location where this diagnostic occurs.
A worklist implementation for backward dataflow analysis.
void enqueuePredecessors(const CFGBlock *Block)
EvalResult is a struct with detailed info about an evaluated expression.
Iterator for iterating over Stmt * arrays that contain only T *.
unsigned NumVariablesAnalyzed