47#include "llvm/ADT/ArrayRef.h"
48#include "llvm/ADT/BitVector.h"
49#include "llvm/ADT/DenseMap.h"
50#include "llvm/ADT/MapVector.h"
51#include "llvm/ADT/STLFunctionalExtras.h"
52#include "llvm/ADT/SmallVector.h"
53#include "llvm/ADT/StringRef.h"
54#include "llvm/Support/Debug.h"
69 SourceRange PreviousSilenceableCondVal;
72 UnreachableCodeHandler(Sema &
s) : S(
s) {}
75 SourceRange SilenceableCondVal, SourceRange R1,
76 SourceRange R2,
bool HasFallThroughAttr)
override {
80 if (HasFallThroughAttr &&
81 !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr,
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()) {
112 SourceLocation Close = SilenceableCondVal.
getEnd();
113 Close = S.getLocForEndOfToken(Close);
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) {
153 for (
const Stmt *SubStmt : E->
children())
154 if (
const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt))
155 if (HasMacroID(SubExpr))
161 void logicAlwaysTrue(
const BinaryOperator *B,
bool isAlwaysTrue)
override {
165 unsigned DiagID = isAlwaysTrue
166 ? diag::warn_tautological_negation_or_compare
167 : diag::warn_tautological_negation_and_compare;
172 void compareAlwaysTrue(
const BinaryOperator *B,
173 bool isAlwaysTrueOrFalse)
override {
178 S.Diag(B->
getExprLoc(), diag::warn_tautological_overlap_comparison)
179 << DiagRange << isAlwaysTrueOrFalse;
182 void compareBitwiseEquality(
const BinaryOperator *B,
183 bool isAlwaysTrue)
override {
188 S.Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_always)
189 << DiagRange << isAlwaysTrue;
192 void compareBitwiseOr(
const BinaryOperator *B)
override {
197 S.Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;
200 static bool hasActiveDiagnostics(DiagnosticsEngine &Diags,
201 SourceLocation Loc) {
202 return !Diags.
isIgnored(diag::warn_tautological_overlap_comparison, Loc) ||
203 !Diags.
isIgnored(diag::warn_comparison_bitwise_or, Loc) ||
204 !Diags.
isIgnored(diag::warn_tautological_negation_and_compare, Loc);
218 for (
const auto &B :
Block) {
232 if (isa_and_nonnull<TemplateSpecializationType>(NNS.getAsType()))
248 bool foundRecursion =
false;
253 WorkList.push_back(&cfg->
getEntry());
255 while (!WorkList.empty()) {
258 for (
auto I =
Block->succ_begin(), E =
Block->succ_end(); I != E; ++I) {
260 if (!Visited.insert(SuccBlock).second)
264 if (ExitID == SuccBlock->getBlockID())
269 foundRecursion =
true;
273 WorkList.push_back(SuccBlock);
277 return foundRecursion;
313 Stack.push_back(&ThrowBlock);
316 while (!Stack.empty()) {
317 CFGBlock &UnwindBlock = *Stack.pop_back_val();
319 for (
auto &Succ : UnwindBlock.
succs()) {
320 if (!Succ.isReachable() || Queued[Succ->getBlockID()])
327 dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
328 QualType Caught = Catch->getCaughtType();
335 Stack.push_back(Succ);
336 Queued[Succ->getBlockID()] =
true;
350 if (!Reachable[B->getBlockID()])
353 std::optional<CFGStmt> S = E.getAs<
CFGStmt>();
356 if (
auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))
366 S.
Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
372 getAs<FunctionProtoType>())
397 if (FPT->isNothrow() || FD->
hasAttr<NoThrowAttr>())
406 if (
auto *FD = dyn_cast<FunctionDecl>(DRef->getDecl()))
407 return FD->isNoReturn();
426struct TransferFunctions :
public StmtVisitor<TransferFunctions> {
428 std::optional<bool> AllValuesAreNoReturn;
430 TransferFunctions(
const VarDecl *VD) : Var(VD) {}
432 void reset() { AllValuesAreNoReturn = std::nullopt; }
434 void VisitDeclStmt(DeclStmt *DS) {
435 for (
auto *DI : DS->
decls())
436 if (
auto *VD = dyn_cast<VarDecl>(DI))
437 if (VarDecl *Def = VD->getDefinition())
442 void VisitUnaryOperator(UnaryOperator *UO) {
446 if (DRef->getDecl() == Var)
447 AllValuesAreNoReturn =
false;
451 void VisitBinaryOperator(BinaryOperator *BO) {
454 if (DRef->getDecl() == Var)
458 void VisitCallExpr(CallExpr *CE) {
461 const Expr *Arg = *I;
464 if (
auto VD = dyn_cast<VarDecl>(DRef->getDecl()))
465 if (VD->getDefinition() == Var)
466 AllValuesAreNoReturn =
false;
492 using MapTy = llvm::DenseMap<const CFGBlock *, std::optional<bool>>;
493 using ValueTy = MapTy::value_type;
495 BlocksToCheck[&VarBlk] = std::nullopt;
496 const auto BlockSatisfiesCondition = [](ValueTy Item) {
497 return Item.getSecond().value_or(
false);
500 TransferFunctions TF(VD);
502 llvm::DenseSet<const CFGBlock *> Visited;
505 if (Visited.contains(B))
511 if (std::optional<CFGStmt> cs = ri->getAs<
CFGStmt>()) {
512 const Stmt *S = cs->getStmt();
514 TF.Visit(
const_cast<Stmt *
>(S));
515 if (TF.AllValuesAreNoReturn) {
516 if (!TF.AllValuesAreNoReturn.value())
518 BlocksToCheck[B] =
true;
525 if (llvm::all_of(BlocksToCheck, BlockSatisfiesCondition))
530 if (!BlocksToCheck[B]) {
532 BlocksToCheck.erase(B);
533 for (
const auto &PredBlk : B->preds())
534 if (!BlocksToCheck.contains(PredBlk))
535 BlocksToCheck[PredBlk] = std::nullopt;
578 for (
const auto *B : *cfg) {
579 if (!live[B->getBlockID()]) {
580 if (B->preds().empty()) {
581 const Stmt *Term = B->getTerminatorStmt();
582 if (isa_and_nonnull<CXXTryStmt>(Term))
594 bool HasLiveReturn =
false;
595 bool HasFakeEdge =
false;
596 bool HasPlainEdge =
false;
597 bool HasAbnormalEdge =
false;
615 HasAbnormalEdge =
true;
624 for ( ; ri != re ; ++ri)
632 HasAbnormalEdge =
true;
643 HasLiveReturn =
true;
657 HasLiveReturn =
true;
661 HasAbnormalEdge =
true;
665 HasAbnormalEdge =
true;
668 if (
auto *
Call = dyn_cast<CallExpr>(S)) {
669 const Expr *Callee =
Call->getCallee();
670 if (Callee->getType()->isPointerType())
672 dyn_cast<DeclRefExpr>(Callee->IgnoreParenImpCasts()))
673 if (
auto *VD = dyn_cast<VarDecl>(DeclRef->getDecl()))
675 HasAbnormalEdge =
true;
687 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
697struct CheckFallThroughDiagnostics {
698 unsigned diag_FallThrough_HasNoReturn = 0;
699 unsigned diag_FallThrough_ReturnsNonVoid = 0;
700 unsigned diag_NeverFallThroughOrReturn = 0;
702 SourceLocation FuncLoc;
704 static CheckFallThroughDiagnostics MakeForFunction(Sema &S,
706 CheckFallThroughDiagnostics D;
707 D.FuncLoc =
Func->getLocation();
708 D.diag_FallThrough_HasNoReturn = diag::warn_noreturn_has_return_expr;
709 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
713 bool isVirtualMethod =
false;
714 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(
Func))
715 isVirtualMethod =
Method->isVirtual();
719 if (
const FunctionDecl *
Function = dyn_cast<FunctionDecl>(
Func)) {
723 D.diag_FallThrough_ReturnsNonVoid = diag::ext_main_no_return;
728 D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function;
730 D.FunKind = diag::FalloffFunctionKind::Function;
734 static CheckFallThroughDiagnostics MakeForCoroutine(
const Decl *
Func) {
735 CheckFallThroughDiagnostics D;
736 D.FuncLoc =
Func->getLocation();
737 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
738 D.FunKind = diag::FalloffFunctionKind::Coroutine;
742 static CheckFallThroughDiagnostics MakeForBlock() {
743 CheckFallThroughDiagnostics D;
744 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;
745 D.diag_FallThrough_ReturnsNonVoid = diag::err_falloff_nonvoid;
746 D.FunKind = diag::FalloffFunctionKind::Block;
750 static CheckFallThroughDiagnostics MakeForLambda() {
751 CheckFallThroughDiagnostics D;
752 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;
753 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
754 D.FunKind = diag::FalloffFunctionKind::Lambda;
758 bool checkDiagnostics(DiagnosticsEngine &D,
bool ReturnsVoid,
759 bool HasNoReturn)
const {
760 if (FunKind == diag::FalloffFunctionKind::Function) {
761 return (ReturnsVoid ||
762 D.
isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&
764 D.
isIgnored(diag::warn_noreturn_has_return_expr, FuncLoc)) &&
766 D.
isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));
768 if (FunKind == diag::FalloffFunctionKind::Coroutine) {
769 return (ReturnsVoid ||
770 D.
isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&
774 return ReturnsVoid && !HasNoReturn;
786 const CheckFallThroughDiagnostics &CD,
789 bool ReturnsVoid =
false;
790 bool HasNoReturn =
false;
792 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
793 if (
const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
794 ReturnsVoid = CBody->getFallthroughHandler() !=
nullptr;
796 ReturnsVoid = FD->getReturnType()->isVoidType();
797 HasNoReturn = FD->isNoReturn() || FD->hasAttr<InferredNoReturnAttr>();
799 else if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
800 ReturnsVoid = MD->getReturnType()->isVoidType();
801 HasNoReturn = MD->hasAttr<NoReturnAttr>();
806 if (FT->getReturnType()->isVoidType())
808 if (FT->getNoReturnAttr())
816 if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
832 if (CD.diag_FallThrough_HasNoReturn)
833 S.
Diag(RBrace, CD.diag_FallThrough_HasNoReturn) << CD.FunKind;
834 }
else if (!ReturnsVoid && CD.diag_FallThrough_ReturnsNonVoid) {
838 if (
const auto *CS = dyn_cast<CompoundStmt>(Body);
839 CS && !CS->body_empty()) {
840 const Stmt *LastStmt = CS->body_back();
842 if (
const auto *EWC = dyn_cast<ExprWithCleanups>(LastStmt)) {
843 LastStmt = EWC->getSubExpr();
845 if (
const auto *CE = dyn_cast<CallExpr>(LastStmt)) {
847 Callee && Callee->hasAttr<InferredNoReturnAttr>()) {
858 S.
Diag(RBrace, CD.diag_FallThrough_ReturnsNonVoid)
859 << CD.FunKind << NotInAllControlPaths;
863 if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
864 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
865 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
866 }
else if (
const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
867 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
869 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
888 const DeclRefExpr *Needle;
891 typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited;
893 ContainsReference(ASTContext &Context,
const DeclRefExpr *Needle)
894 : Inherited(Context), FoundReference(
false), Needle(Needle) {}
896 void VisitExpr(
const Expr *E) {
901 Inherited::VisitExpr(E);
904 void VisitDeclRefExpr(
const DeclRefExpr *E) {
906 FoundReference =
true;
911 bool doesContainReference()
const {
return FoundReference; }
919 S.
Diag(VD->
getLocation(), diag::note_block_var_fixit_add_initialization)
940 S.
Diag(Loc, diag::note_var_fixit_add_initialization) << VD->
getDeclName()
948 const Stmt *Else,
bool CondVal,
972 bool IsCapturedByBlock) {
973 bool Diagnosed =
false;
1005 const Stmt *Term = I->Terminator;
1015 int RemoveDiagKind = -1;
1016 const char *FixitStr =
1017 S.
getLangOpts().CPlusPlus ? (I->Output ?
"true" :
"false")
1018 : (I->Output ?
"1" :
"0");
1021 switch (Term ? Term->
getStmtClass() : Stmt::DeclStmtClass) {
1028 case Stmt::IfStmtClass: {
1035 I->Output, Fixit1, Fixit2);
1038 case Stmt::ConditionalOperatorClass: {
1045 I->Output, Fixit1, Fixit2);
1048 case Stmt::BinaryOperatorClass: {
1056 if ((BO->
getOpcode() == BO_LAnd && I->Output) ||
1057 (BO->
getOpcode() == BO_LOr && !I->Output))
1068 case Stmt::WhileStmtClass:
1075 case Stmt::ForStmtClass:
1085 case Stmt::CXXForRangeStmtClass:
1086 if (I->Output == 1) {
1098 case Stmt::DoStmtClass:
1101 Range =
cast<DoStmt>(Term)->getCond()->getSourceRange();
1107 case Stmt::CaseStmtClass:
1112 case Stmt::DefaultStmtClass:
1119 S.
Diag(Range.getBegin(), diag::warn_sometimes_uninit_var)
1120 << VD->
getDeclName() << IsCapturedByBlock << DiagKind
1121 << Str << I->Output << Range;
1124 if (RemoveDiagKind != -1)
1126 << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
1160 bool alwaysReportSelfInit =
false) {
1174 if (!alwaysReportSelfInit && DRE ==
Initializer->IgnoreParenImpCasts())
1177 ContainsReference CR(S.
Context, DRE);
1179 if (CR.doesContainReference()) {
1180 S.
Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
1191 diag::warn_uninit_byref_blockvar_captured_by_block)
1211 FallthroughMapper(Sema &S) : FoundSwitchStatements(
false), S(S) {
1212 ShouldWalkTypesOfTypeLocs =
false;
1215 bool foundSwitchStatements()
const {
return FoundSwitchStatements; }
1217 void markFallthroughVisited(
const AttributedStmt *Stmt) {
1218 bool Found = FallthroughStmts.erase(Stmt);
1223 typedef llvm::SmallPtrSet<const AttributedStmt *, 8> AttrStmts;
1225 const AttrStmts &getFallthroughStmts()
const {
return FallthroughStmts; }
1227 void fillReachableBlocks(CFG *Cfg) {
1228 assert(ReachableBlocks.empty() &&
"ReachableBlocks already filled");
1229 std::deque<const CFGBlock *> BlockQueue;
1231 ReachableBlocks.insert(&Cfg->
getEntry());
1232 BlockQueue.push_back(&Cfg->
getEntry());
1237 for (
const auto *B : *Cfg) {
1238 const Stmt *L = B->getLabel();
1239 if (isa_and_nonnull<SwitchCase>(L) && ReachableBlocks.insert(B).second)
1240 BlockQueue.push_back(B);
1243 while (!BlockQueue.empty()) {
1244 const CFGBlock *P = BlockQueue.front();
1245 BlockQueue.pop_front();
1246 for (
const CFGBlock *B : P->
succs()) {
1247 if (B && ReachableBlocks.insert(B).second)
1248 BlockQueue.push_back(B);
1253 bool checkFallThroughIntoBlock(
const CFGBlock &B,
int &AnnotatedCnt,
1254 bool IsTemplateInstantiation) {
1255 assert(!ReachableBlocks.empty() &&
"ReachableBlocks empty");
1257 int UnannotatedCnt = 0;
1261 while (!BlockQueue.empty()) {
1262 const CFGBlock *P = BlockQueue.
front();
1263 BlockQueue.pop_front();
1268 if (isa_and_nonnull<SwitchStmt>(Term))
1271 const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->
getLabel());
1275 const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->
getLabel());
1279 if (!ReachableBlocks.count(P)) {
1280 for (
const CFGElement &Elem : llvm::reverse(*P)) {
1281 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) {
1282 if (
const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
1286 if (!IsTemplateInstantiation)
1287 S.Diag(AS->getBeginLoc(),
1288 diag::warn_unreachable_fallthrough_attr);
1289 markFallthroughVisited(AS);
1308 if (
const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {
1309 markFallthroughVisited(AS);
1317 std::back_inserter(BlockQueue));
1323 return !!UnannotatedCnt;
1326 bool VisitAttributedStmt(AttributedStmt *S)
override {
1327 if (asFallThroughAttr(S))
1328 FallthroughStmts.insert(S);
1332 bool VisitSwitchStmt(SwitchStmt *S)
override {
1333 FoundSwitchStatements =
true;
1339 bool TraverseDecl(Decl *D)
override {
return true; }
1342 bool TraverseLambdaExpr(
LambdaExpr *LE)
override {
1344 for (
const auto C : zip(
LE->captures(),
LE->capture_inits()))
1345 TraverseLambdaCapture(LE, &std::get<0>(
C), std::get<1>(
C));
1351 static const AttributedStmt *asFallThroughAttr(
const Stmt *S) {
1352 if (
const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
1359 static const Stmt *
getLastStmt(
const CFGBlock &B) {
1362 for (
const CFGElement &Elem : llvm::reverse(B))
1363 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
1364 return CS->getStmt();
1368 if (
const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.
getLabel()))
1375 bool FoundSwitchStatements;
1376 AttrStmts FallthroughStmts;
1378 llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
1385 tok::l_square, tok::l_square,
1387 tok::r_square, tok::r_square
1393 tok::r_square, tok::r_square
1398 StringRef MacroName;
1399 if (PreferClangAttr)
1401 if (MacroName.empty())
1403 if (MacroName.empty() && !PreferClangAttr)
1405 if (MacroName.empty()) {
1406 if (!PreferClangAttr)
1407 MacroName =
"[[fallthrough]]";
1409 MacroName =
"[[clang::fallthrough]]";
1411 MacroName =
"__attribute__((fallthrough))";
1418 FallthroughMapper FM(S);
1419 FM.TraverseStmt(AC.
getBody());
1421 if (!FM.foundSwitchStatements())
1424 if (PerFunction && FM.getFallthroughStmts().empty())
1432 FM.fillReachableBlocks(Cfg);
1434 for (
const CFGBlock *B : llvm::reverse(*Cfg)) {
1437 if (!isa_and_nonnull<SwitchCase>(Label))
1442 bool IsTemplateInstantiation =
false;
1444 IsTemplateInstantiation = Function->isTemplateInstantiation();
1445 if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,
1446 IsTemplateInstantiation))
1450 PerFunction ? diag::warn_unannotated_fallthrough_per_function
1451 : diag::warn_unannotated_fallthrough);
1453 if (!AnnotatedCnt) {
1464 if (!(B->
empty() && isa_and_nonnull<BreakStmt>(Term))) {
1468 TextToInsert +=
"; ";
1469 S.
Diag(L, diag::note_insert_fallthrough_fixit)
1470 << AnnotationSpelling
1473 S.
Diag(L, diag::note_insert_break_fixit)
1478 for (
const auto *F : FM.getFallthroughStmts())
1479 S.
Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement);
1488 case Stmt::ForStmtClass:
1489 case Stmt::WhileStmtClass:
1490 case Stmt::CXXForRangeStmtClass:
1491 case Stmt::ObjCForCollectionStmtClass:
1493 case Stmt::DoStmtClass: {
1497 return Result.
Val.
getInt().getBoolValue();
1514 typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
1523 for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end();
1525 const WeakUseVector &Uses = I->second;
1528 WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
1529 for ( ; UI != UE; ++UI) {
1542 if (UI == Uses.begin()) {
1543 WeakUseVector::const_iterator UI2 = UI;
1544 for (++UI2; UI2 != UE; ++UI2)
1545 if (UI2->isUnsafe())
1549 if (!
isInLoop(Ctx, PM, UI->getUseExpr()))
1552 const WeakObjectProfileTy &Profile = I->first;
1553 if (!Profile.isExactProfile())
1558 Base = Profile.getProperty();
1559 assert(
Base &&
"A profile always has a base or property.");
1561 if (
const VarDecl *BaseVar = dyn_cast<VarDecl>(
Base))
1567 UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
1570 if (UsesByStmt.empty())
1575 llvm::sort(UsesByStmt,
1576 [&
SM](
const StmtUsesPair &LHS,
const StmtUsesPair &RHS) {
1577 return SM.isBeforeInTranslationUnit(LHS.first->getBeginLoc(),
1578 RHS.first->getBeginLoc());
1594 FunctionKind =
Block;
1596 FunctionKind = Lambda;
1598 FunctionKind = Method;
1600 FunctionKind = Function;
1603 for (
const auto &P : UsesByStmt) {
1604 const Stmt *FirstRead = P.first;
1605 const WeakObjectProfileTy &Key = P.second->first;
1606 const WeakUseVector &Uses = P.second->second;
1614 if (Key.isExactProfile())
1615 DiagKind = diag::warn_arc_repeated_use_of_weak;
1617 DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
1629 const NamedDecl *KeyProp = Key.getProperty();
1631 ObjectKind = Variable;
1633 ObjectKind = Property;
1635 ObjectKind = ImplicitProperty;
1639 llvm_unreachable(
"Unexpected weak object kind!");
1644 if (Prop->hasAttr<IBOutletAttr>())
1649 <<
int(ObjectKind) << KeyProp <<
int(FunctionKind)
1653 for (
const auto &Use : Uses) {
1654 if (Use.getUseExpr() == FirstRead)
1656 S.
Diag(Use.getUseExpr()->getBeginLoc(),
1657 diag::note_arc_weak_also_accessed_here)
1658 << Use.getUseExpr()->getSourceRange();
1666typedef std::pair<PartialDiagnosticAt, OptionalNotes>
DelayedDiag;
1667typedef std::list<DelayedDiag>
DiagList;
1669struct SortDiagBySourceLocation {
1671 SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {}
1673 bool operator()(
const DelayedDiag &left,
const DelayedDiag &right) {
1676 return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
1685 typedef SmallVector<UninitUse, 2> UsesVec;
1686 typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
1690 typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
1694 UninitValsDiagReporter(Sema &S) : S(S) {}
1697 MappedType &getUses(
const VarDecl *vd) {
1698 MappedType &
V = uses[vd];
1699 if (!
V.getPointer())
1700 V.setPointer(
new UsesVec());
1704 void handleUseOfUninitVariable(
const VarDecl *vd,
1705 const UninitUse &use)
override {
1706 getUses(vd).getPointer()->push_back(use);
1709 void handleSelfInit(
const VarDecl *vd)
override { getUses(vd).setInt(
true); }
1712 for (
const auto &P : uses) {
1713 const VarDecl *vd = P.first;
1714 const MappedType &
V = P.second;
1716 UsesVec *vec =
V.getPointer();
1717 bool hasSelfInit =
V.getInt();
1719 diagnoseUnitializedVar(vd, hasSelfInit, vec);
1729 static bool hasAlwaysUninitializedUse(
const UsesVec* vec) {
1730 return llvm::any_of(*vec, [](
const UninitUse &U) {
1740 void diagnoseUnitializedVar(
const VarDecl *vd,
bool hasSelfInit,
1745 if (hasSelfInit && hasAlwaysUninitializedUse(vec)) {
1756 llvm::sort(*vec, [](
const UninitUse &a,
const UninitUse &
b) {
1760 return b.isConstRefOrPtrUse();
1767 for (
const auto &U : *vec) {
1776 UninitUse Use = hasSelfInit ? UninitUse(U.
getUser(),
false) : U;
1785class CalledOnceInterProceduralData {
1788 void addDelayedWarning(
const BlockDecl *
Block,
1790 DelayedBlockWarnings[
Block].emplace_back(std::move(
Warning));
1793 void flushWarnings(
const BlockDecl *
Block, Sema &S) {
1795 S.
Diag(Delayed.first, Delayed.second);
1797 discardWarnings(
Block);
1800 void discardWarnings(
const BlockDecl *
Block) {
1801 DelayedBlockWarnings.erase(
Block);
1805 using DelayedDiagnostics = SmallVector<PartialDiagnosticAt, 2>;
1806 llvm::DenseMap<const BlockDecl *, DelayedDiagnostics> DelayedBlockWarnings;
1811 CalledOnceCheckReporter(Sema &S, CalledOnceInterProceduralData &Data)
1812 : S(S), Data(Data) {}
1813 void handleDoubleCall(
const ParmVarDecl *
Parameter,
const Expr *
Call,
1814 const Expr *PrevCall,
bool IsCompletionHandler,
1815 bool Poised)
override {
1816 auto DiagToReport = IsCompletionHandler
1817 ? diag::warn_completion_handler_called_twice
1818 : diag::warn_called_once_gets_called_twice;
1820 S.Diag(PrevCall->
getBeginLoc(), diag::note_called_once_gets_called_twice)
1824 void handleNeverCalled(
const ParmVarDecl *
Parameter,
1825 bool IsCompletionHandler)
override {
1826 auto DiagToReport = IsCompletionHandler
1827 ? diag::warn_completion_handler_never_called
1828 : diag::warn_called_once_never_called;
1829 S.Diag(
Parameter->getBeginLoc(), DiagToReport)
1835 bool IsCalledDirectly,
1836 bool IsCompletionHandler)
override {
1837 auto DiagToReport = IsCompletionHandler
1838 ? diag::warn_completion_handler_never_called_when
1839 : diag::warn_called_once_never_called_when;
1843 << (
unsigned)Reason);
1853 void handleCapturedNeverCalled(
const ParmVarDecl *
Parameter,
1855 bool IsCompletionHandler)
override {
1856 auto DiagToReport = IsCompletionHandler
1857 ? diag::warn_completion_handler_never_called
1858 : diag::warn_called_once_never_called;
1864 handleBlockThatIsGuaranteedToBeCalledOnce(
const BlockDecl *
Block)
override {
1865 Data.flushWarnings(
Block, S);
1868 void handleBlockWithNoGuarantees(
const BlockDecl *
Block)
override {
1869 Data.discardWarnings(
Block);
1874 CalledOnceInterProceduralData &Data;
1877constexpr unsigned CalledOnceWarnings[] = {
1878 diag::warn_called_once_never_called,
1879 diag::warn_called_once_never_called_when,
1880 diag::warn_called_once_gets_called_twice};
1882constexpr unsigned CompletionHandlerWarnings[]{
1883 diag::warn_completion_handler_never_called,
1884 diag::warn_completion_handler_never_called_when,
1885 diag::warn_completion_handler_called_twice};
1890 return llvm::any_of(DiagIDs, [&Diags, At](
unsigned DiagID) {
1897 return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);
1902 return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||
1903 shouldAnalyzeCalledOnceConventions(Diags, At);
1913class ThreadSafetyReporter :
public clang::threadSafety::ThreadSafetyHandler {
1916 SourceLocation FunLocation, FunEndLocation;
1918 const FunctionDecl *CurrentFunction;
1922 if (Verbose && CurrentFunction) {
1924 S.PDiag(diag::note_thread_warning_in_fun)
1925 << CurrentFunction);
1933 if (Verbose && CurrentFunction) {
1935 S.PDiag(diag::note_thread_warning_in_fun)
1936 << CurrentFunction);
1937 ONS.push_back(std::move(FNote));
1945 ONS.push_back(Note1);
1946 ONS.push_back(Note2);
1947 if (Verbose && CurrentFunction) {
1949 S.PDiag(diag::note_thread_warning_in_fun)
1950 << CurrentFunction);
1951 ONS.push_back(std::move(FNote));
1956 OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) {
1959 LocLocked, S.PDiag(diag::note_locked_here) << Kind))
1963 OptionalNotes makeUnlockedHereNote(SourceLocation LocUnlocked,
1967 LocUnlocked, S.PDiag(diag::note_unlocked_here) << Kind))
1971 OptionalNotes makeManagedMismatchNoteForParam(SourceLocation DeclLoc) {
1975 S.PDiag(diag::note_managed_mismatch_here_for_param)))
1980 ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
1981 : S(S), FunLocation(FL), FunEndLocation(FEL),
1984 void setVerbose(
bool b) { Verbose =
b; }
1991 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
1992 for (
const auto &
Diag : Warnings) {
1993 S.Diag(
Diag.first.first,
Diag.first.second);
1994 for (
const auto &
Note :
Diag.second)
1999 void handleUnmatchedUnderlyingMutexes(SourceLocation Loc, SourceLocation DLoc,
2000 Name scopeName, StringRef Kind,
2001 Name expected, Name actual)
override {
2003 S.PDiag(diag::warn_unmatched_underlying_mutexes)
2004 << Kind << scopeName << expected << actual);
2005 Warnings.emplace_back(std::move(
Warning),
2006 makeManagedMismatchNoteForParam(DLoc));
2009 void handleExpectMoreUnderlyingMutexes(SourceLocation Loc,
2010 SourceLocation DLoc, Name scopeName,
2012 Name expected)
override {
2014 Loc, S.PDiag(diag::warn_expect_more_underlying_mutexes)
2015 << Kind << scopeName << expected);
2016 Warnings.emplace_back(std::move(
Warning),
2017 makeManagedMismatchNoteForParam(DLoc));
2020 void handleExpectFewerUnderlyingMutexes(SourceLocation Loc,
2021 SourceLocation DLoc, Name scopeName,
2023 Name actual)
override {
2025 Loc, S.PDiag(diag::warn_expect_fewer_underlying_mutexes)
2026 << Kind << scopeName << actual);
2027 Warnings.emplace_back(std::move(
Warning),
2028 makeManagedMismatchNoteForParam(DLoc));
2031 void handleInvalidLockExp(SourceLocation Loc)
override {
2034 Warnings.emplace_back(std::move(
Warning), getNotes());
2037 void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc,
2038 SourceLocation LocPreviousUnlock)
override {
2042 << Kind << LockName);
2043 Warnings.emplace_back(std::move(
Warning),
2044 makeUnlockedHereNote(LocPreviousUnlock, Kind));
2047 void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
2049 SourceLocation LocLocked,
2050 SourceLocation LocUnlock)
override {
2052 LocUnlock = FunLocation;
2054 LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch)
2055 << Kind << LockName << Received << Expected);
2056 Warnings.emplace_back(std::move(
Warning),
2057 makeLockedHereNote(LocLocked, Kind));
2060 void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked,
2061 SourceLocation LocDoubleLock)
override {
2063 LocDoubleLock = FunLocation;
2065 << Kind << LockName);
2066 Warnings.emplace_back(std::move(
Warning),
2067 makeLockedHereNote(LocLocked, Kind));
2070 void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
2071 SourceLocation LocLocked,
2072 SourceLocation LocEndOfScope,
2074 bool ReentrancyMismatch)
override {
2075 unsigned DiagID = 0;
2078 DiagID = diag::warn_lock_some_predecessors;
2081 DiagID = diag::warn_expecting_lock_held_on_loop;
2084 DiagID = diag::warn_no_unlock;
2087 DiagID = diag::warn_expecting_locked;
2091 LocEndOfScope = FunEndLocation;
2095 << ReentrancyMismatch);
2096 Warnings.emplace_back(std::move(
Warning),
2097 makeLockedHereNote(LocLocked, Kind));
2100 void handleExclusiveAndShared(StringRef Kind, Name LockName,
2101 SourceLocation Loc1,
2102 SourceLocation Loc2)
override {
2104 S.PDiag(diag::warn_lock_exclusive_and_shared)
2105 << Kind << LockName);
2107 << Kind << LockName);
2108 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2112 AccessKind AK, SourceLocation Loc)
override {
2113 unsigned DiagID = 0;
2120 DiagID = diag::warn_variable_requires_any_lock;
2127 DiagID = diag::warn_var_deref_requires_any_lock;
2130 llvm_unreachable(
"Only works for variables");
2135 Warnings.emplace_back(std::move(
Warning), getNotes());
2138 void handleMutexNotHeld(StringRef Kind,
const NamedDecl *D,
2141 Name *PossibleMatch)
override {
2142 unsigned DiagID = 0;
2143 if (PossibleMatch) {
2146 DiagID = diag::warn_variable_requires_lock_precise;
2149 DiagID = diag::warn_var_deref_requires_lock_precise;
2152 DiagID = diag::warn_fun_requires_lock_precise;
2155 DiagID = diag::warn_guarded_pass_by_reference;
2158 DiagID = diag::warn_pt_guarded_pass_by_reference;
2161 DiagID = diag::warn_guarded_return_by_reference;
2164 DiagID = diag::warn_pt_guarded_return_by_reference;
2167 DiagID = diag::warn_guarded_pass_pointer;
2170 DiagID = diag::warn_pt_guarded_pass_pointer;
2173 DiagID = diag::warn_guarded_return_pointer;
2176 DiagID = diag::warn_pt_guarded_return_pointer;
2186 S.PDiag(diag::note_guarded_by_declared_here)
2188 Warnings.emplace_back(std::move(
Warning), getNotes(
Note, VNote));
2190 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2194 DiagID = diag::warn_variable_requires_lock;
2197 DiagID = diag::warn_var_deref_requires_lock;
2200 DiagID = diag::warn_fun_requires_lock;
2203 DiagID = diag::warn_guarded_pass_by_reference;
2206 DiagID = diag::warn_pt_guarded_pass_by_reference;
2209 DiagID = diag::warn_guarded_return_by_reference;
2212 DiagID = diag::warn_pt_guarded_return_by_reference;
2215 DiagID = diag::warn_guarded_pass_pointer;
2218 DiagID = diag::warn_pt_guarded_pass_pointer;
2221 DiagID = diag::warn_guarded_return_pointer;
2224 DiagID = diag::warn_pt_guarded_return_pointer;
2232 S.PDiag(diag::note_guarded_by_declared_here));
2233 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2235 Warnings.emplace_back(std::move(
Warning), getNotes());
2239 void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
2240 SourceLocation Loc)
override {
2242 S.PDiag(diag::warn_acquire_requires_negative_cap)
2243 << Kind << LockName << Neg);
2244 Warnings.emplace_back(std::move(
Warning), getNotes());
2247 void handleNegativeNotHeld(
const NamedDecl *D, Name LockName,
2248 SourceLocation Loc)
override {
2250 Loc, S.PDiag(diag::warn_fun_requires_negative_cap) << D << LockName);
2251 Warnings.emplace_back(std::move(
Warning), getNotes());
2254 void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
2255 SourceLocation Loc)
override {
2257 << Kind << FunName << LockName);
2258 Warnings.emplace_back(std::move(
Warning), getNotes());
2261 void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
2262 SourceLocation Loc)
override {
2264 S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
2265 Warnings.emplace_back(std::move(
Warning), getNotes());
2268 void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc)
override {
2270 S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
2271 Warnings.emplace_back(std::move(
Warning), getNotes());
2274 void enterFunction(
const FunctionDecl* FD)
override {
2275 CurrentFunction = FD;
2278 void leaveFunction(
const FunctionDecl* FD)
override {
2279 CurrentFunction =
nullptr;
2300 ConsumedWarningsHandler(Sema &S) : S(S) {}
2303 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
2304 for (
const auto &
Diag : Warnings) {
2305 S.Diag(
Diag.first.first,
Diag.first.second);
2306 for (
const auto &
Note :
Diag.second)
2311 void warnLoopStateMismatch(SourceLocation Loc,
2312 StringRef VariableName)
override {
2319 void warnParamReturnTypestateMismatch(SourceLocation Loc,
2320 StringRef VariableName,
2321 StringRef ExpectedState,
2322 StringRef ObservedState)
override {
2325 diag::warn_param_return_typestate_mismatch) << VariableName <<
2326 ExpectedState << ObservedState);
2331 void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
2332 StringRef ObservedState)
override {
2335 diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
2340 void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
2341 StringRef TypeName)
override {
2343 diag::warn_return_typestate_for_unconsumable_type) << TypeName);
2348 void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
2349 StringRef ObservedState)
override {
2352 diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
2357 void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
2358 SourceLocation Loc)
override {
2361 diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
2366 void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
2367 StringRef State, SourceLocation Loc)
override {
2370 MethodName << VariableName << State);
2386 bool SuggestSuggestions;
2390 std::string listVariableGroupAsString(
2391 const VarDecl *VD,
const ArrayRef<const VarDecl *> &VarGroupForVD)
const {
2392 if (VarGroupForVD.size() <= 1)
2395 std::vector<StringRef> VarNames;
2396 auto PutInQuotes = [](StringRef S) -> std::string {
2397 return "'" + S.str() +
"'";
2400 for (
auto *
V : VarGroupForVD) {
2403 VarNames.push_back(
V->getName());
2405 if (VarNames.size() == 1) {
2406 return PutInQuotes(VarNames[0]);
2408 if (VarNames.size() == 2) {
2409 return PutInQuotes(VarNames[0]) +
" and " + PutInQuotes(VarNames[1]);
2411 assert(VarGroupForVD.size() > 3);
2412 const unsigned N = VarNames.size() -
2414 std::string AllVars =
"";
2416 for (
unsigned I = 0; I < N; ++I)
2417 AllVars.append(PutInQuotes(VarNames[I]) +
", ");
2418 AllVars.append(PutInQuotes(VarNames[N]) +
", and " +
2419 PutInQuotes(VarNames[N + 1]));
2424 UnsafeBufferUsageReporter(Sema &S,
bool SuggestSuggestions)
2425 : S(S), SuggestSuggestions(SuggestSuggestions) {}
2427 void handleUnsafeOperation(
const Stmt *Operation,
bool IsRelatedToDecl,
2428 ASTContext &Ctx)
override {
2431 unsigned MsgParam = 0;
2432 NamedDecl *D =
nullptr;
2433 if (
const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
2434 Loc = ASE->getBase()->getExprLoc();
2435 Range = ASE->getBase()->getSourceRange();
2437 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
2439 if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
2440 Op == BO_SubAssign) {
2450 }
else if (
const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
2452 if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
2461 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2465 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2467 D = ME->getMemberDecl();
2469 }
else if (
const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) {
2470 QualType destType = ECE->getType();
2471 bool destTypeComplete =
true;
2477 destTypeComplete = D->isCompleteDefinition();
2481 if (destTypeComplete) {
2483 QualType srcType = ECE->getSubExpr()->getType();
2493 if (
const auto *CE = dyn_cast<CXXMemberCallExpr>(
2494 ECE->getSubExpr()->IgnoreParens())) {
2495 D = CE->getMethodDecl();
2506 if (IsRelatedToDecl) {
2507 assert(!SuggestSuggestions &&
2508 "Variables blamed for unsafe buffer usage without suggestions!");
2509 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2512 S.Diag(Loc, diag::warn_unsafe_buffer_operation)
2513 << MsgParam << D <<
Range;
2515 S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam <<
Range;
2517 if (SuggestSuggestions) {
2518 S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled);
2523 void handleUnsafeLibcCall(
const CallExpr *
Call,
unsigned PrintfInfo,
2525 const Expr *UnsafeArg =
nullptr)
override {
2526 S.Diag(
Call->getBeginLoc(), diag::warn_unsafe_buffer_libc_call)
2527 <<
Call->getDirectCallee()
2529 if (PrintfInfo > 0) {
2531 UnsafeArg ? UnsafeArg->getSourceRange() :
Call->getSourceRange();
2532 S.Diag(R.
getBegin(), diag::note_unsafe_buffer_printf_call)
2537 void handleUnsafeOperationInContainer(
const Stmt *Operation,
2538 bool IsRelatedToDecl,
2539 ASTContext &Ctx)
override {
2542 unsigned MsgParam = 0;
2547 Loc = CtorExpr->getLocation();
2549 S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container);
2550 if (IsRelatedToDecl) {
2551 assert(!SuggestSuggestions &&
2552 "Variables blamed for unsafe buffer usage without suggestions!");
2553 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2557 void handleUnsafeVariableGroup(
const VarDecl *Variable,
2558 const VariableGroupsManager &VarGrpMgr,
2559 FixItList &&Fixes,
const Decl *D,
2560 const FixitStrategy &VarTargetTypes)
override {
2561 assert(!SuggestSuggestions &&
2562 "Unsafe buffer usage fixits displayed without suggestions!");
2563 S.Diag(
Variable->getLocation(), diag::warn_unsafe_buffer_variable)
2566 if (!Fixes.empty()) {
2568 "Fix-its are generated only for `NamedDecl`s");
2570 bool BriefMsg =
false;
2574 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Variable, &BriefMsg);
2575 unsigned FixItStrategy = 0;
2576 switch (VarTargetTypes.
lookup(Variable)) {
2584 assert(
false &&
"We support only std::span and std::array");
2589 BriefMsg ? diag::note_unsafe_buffer_variable_fixit_together
2590 : diag::note_unsafe_buffer_variable_fixit_group);
2593 FD << listVariableGroupAsString(Variable, VarGroupForVD)
2594 << (VarGroupForVD.size() > 1) << ND;
2595 for (
const auto &F : Fixes) {
2601 if (areDebugNotesRequested())
2602 for (
const DebugNote &
Note: DebugNotesByVar[Variable])
2603 S.Diag(
Note.first, diag::note_safe_buffer_debug_mode) <<
Note.second;
2607 void handleUnsafeUniquePtrArrayAccess(
const DynTypedNode &Node,
2608 bool IsRelatedToDecl,
2609 ASTContext &Ctx)
override {
2612 Loc = Node.
get<Stmt>()->getBeginLoc();
2613 S.Diag(Loc, diag::warn_unsafe_buffer_usage_unique_ptr_array_access)
2617 bool isSafeBufferOptOut(
const SourceLocation &Loc)
const override {
2618 return S.PP.isSafeBufferOptOut(S.getSourceManager(), Loc);
2622 return S.Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container, Loc);
2625 bool ignoreUnsafeBufferInLibcCall(
const SourceLocation &Loc)
const override {
2626 return S.Diags.isIgnored(diag::warn_unsafe_buffer_libc_call, Loc);
2633 getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,
2634 StringRef WSSuffix =
"")
const override {
2635 Preprocessor &PP = S.getPreprocessor();
2636 TokenValue ClangUnsafeBufferUsageTokens[] = {
2645 StringRef MacroName;
2649 if (MacroName.empty())
2650 MacroName =
"[[clang::unsafe_buffer_usage]]";
2651 return MacroName.str() + WSSuffix.str();
2662 enableCheckFallThrough = 1;
2663 enableCheckUnreachable = 0;
2664 enableThreadSafetyAnalysis = 0;
2665 enableConsumedAnalysis = 0;
2686template <
typename... Ts>
2689 return (!D.
isIgnored(Diags, Loc) || ...);
2694 NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),
2695 MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),
2696 NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
2697 NumUninitAnalysisBlockVisits(0),
2698 MaxUninitAnalysisBlockVisitsPerFunction(0) {
2706 using namespace diag;
2712 P.enableCheckUnreachable =
2713 PolicyOverrides.enableCheckUnreachable ||
2714 areAnyEnabled(D, Loc, warn_unreachable, warn_unreachable_break,
2715 warn_unreachable_return, warn_unreachable_loop_increment);
2717 P.enableThreadSafetyAnalysis = PolicyOverrides.enableThreadSafetyAnalysis ||
2720 P.enableConsumedAnalysis = PolicyOverrides.enableConsumedAnalysis ||
2725void sema::AnalysisBasedWarnings::clearOverrides() {
2726 PolicyOverrides.enableCheckUnreachable =
false;
2727 PolicyOverrides.enableConsumedAnalysis =
false;
2728 PolicyOverrides.enableThreadSafetyAnalysis =
false;
2733 S.
Diag(D.Loc, D.PD);
2736template <
typename Iterator>
2738 std::pair<Iterator, Iterator> PUDs) {
2740 if (PUDs.first == PUDs.second)
2743 for (
auto I = PUDs.first; I != PUDs.second; ++I) {
2744 for (
const Stmt *S : I->Stmts)
2752 for (
auto I = PUDs.first; I != PUDs.second; ++I) {
2754 if (llvm::all_of(D.Stmts, [&](
const Stmt *St) {
2755 const CFGBlock *Block = AC.getBlockForRegisteredExpression(St);
2759 if (Block && Analysis)
2760 if (!Analysis->isReachable(&AC.getCFG()->getEntry(), Block))
2764 S.
Diag(D.Loc, D.PD);
2768 for (
auto I = PUDs.first; I != PUDs.second; ++I)
2769 S.
Diag(I->Loc, I->PD);
2775 VarDeclPossiblyUnreachableDiags.emplace(VD, PUD);
2780 if (!llvm::is_contained(VarDeclPossiblyUnreachableDiags, VD))
2793 auto Range = VarDeclPossiblyUnreachableDiags.equal_range(VD);
2795 llvm::make_second_range(llvm::make_range(Range.first, Range.second));
2797 S, AC, std::make_pair(SecondRange.begin(), SecondRange.end()));
2804 llvm::function_ref<void(
const Decl *)> Callback;
2805 const Module *
const TUModule;
2809 const Module *
const TUModule)
2810 : Callback(Callback), TUModule(TUModule) {
2855namespace clang::lifetimes {
2857class LifetimeSafetyReporterImpl :
public LifetimeSafetyReporter {
2860 LifetimeSafetyReporterImpl(Sema &S) : S(S) {}
2862 void reportUseAfterFree(
const Expr *IssueExpr,
const Expr *UseExpr,
2863 SourceLocation FreeLoc, Confidence
C)
override {
2865 C == Confidence::Definite
2866 ? diag::warn_lifetime_safety_loan_expires_permissive
2867 : diag::warn_lifetime_safety_loan_expires_strict)
2869 S.
Diag(FreeLoc, diag::note_lifetime_safety_destroyed_here);
2870 S.
Diag(UseExpr->
getExprLoc(), diag::note_lifetime_safety_used_here)
2874 void reportUseAfterReturn(
const Expr *IssueExpr,
const Expr *EscapeExpr,
2875 SourceLocation ExpiryLoc, Confidence
C)
override {
2877 C == Confidence::Definite
2878 ? diag::warn_lifetime_safety_return_stack_addr_permissive
2879 : diag::warn_lifetime_safety_return_stack_addr_strict)
2882 S.
Diag(EscapeExpr->
getExprLoc(), diag::note_lifetime_safety_returned_here)
2906 bool UnsafeBufferUsageCanEmitSuggestions = S.getLangOpts().CPlusPlus20;
2907 bool UnsafeBufferUsageShouldEmitSuggestions =
2908 UnsafeBufferUsageCanEmitSuggestions &&
2909 DiagOpts.ShowSafeBufferUsageSuggestions;
2910 bool UnsafeBufferUsageShouldSuggestSuggestions =
2911 UnsafeBufferUsageCanEmitSuggestions &&
2912 !DiagOpts.ShowSafeBufferUsageSuggestions;
2913 UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions);
2916 auto CallAnalyzers = [&](
const Decl *Node) ->
void {
2917 if (Node->hasAttr<UnsafeBufferUsageAttr>())
2921 if (!Diags.
isIgnored(diag::warn_unsafe_buffer_operation,
2922 Node->getBeginLoc()) ||
2923 !Diags.
isIgnored(diag::warn_unsafe_buffer_variable,
2924 Node->getBeginLoc()) ||
2925 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2926 Node->getBeginLoc()) ||
2927 !Diags.
isIgnored(diag::warn_unsafe_buffer_libc_call,
2928 Node->getBeginLoc())) {
2930 UnsafeBufferUsageShouldEmitSuggestions);
2939 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2942 S.getLangOpts().CPlusPlus )) {
2944 .TraverseTranslationUnitDecl(TU);
2970 if (S.hasUncompilableErrorOccurred()) {
2992 bool EnableLifetimeSafetyAnalysis = S.getLangOpts().EnableLifetimeSafety;
2994 if (EnableLifetimeSafetyAnalysis)
3003 if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||
3004 P.enableConsumedAnalysis || EnableLifetimeSafetyAnalysis) {
3019 std::optional<LogicalErrorHandler> LEH;
3020 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->
getBeginLoc())) {
3030 if (P.enableCheckFallThrough) {
3031 const CheckFallThroughDiagnostics &CD =
3036 ? CheckFallThroughDiagnostics::MakeForLambda()
3038 ? CheckFallThroughDiagnostics::MakeForCoroutine(D)
3039 : CheckFallThroughDiagnostics::MakeForFunction(S, D)));
3044 if (P.enableCheckUnreachable) {
3057 if (P.enableThreadSafetyAnalysis) {
3060 threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
3062 Reporter.setIssueBetaWarnings(
true);
3064 Reporter.setVerbose(
true);
3067 &S.ThreadSafetyDeclCache);
3068 Reporter.emitDiagnostics();
3072 if (P.enableConsumedAnalysis) {
3073 consumed::ConsumedWarningsHandler WarningHandler(S);
3084 UninitValsDiagReporter reporter(S);
3091 ++NumUninitAnalysisFunctions;
3094 MaxUninitAnalysisVariablesPerFunction =
3095 std::max(MaxUninitAnalysisVariablesPerFunction,
3097 MaxUninitAnalysisBlockVisitsPerFunction =
3098 std::max(MaxUninitAnalysisBlockVisitsPerFunction,
3106 if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {
3108 lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);
3113 if (S.getLangOpts().ObjC && !S.getLangOpts().CPlusPlus &&
3114 shouldAnalyzeCalledOnceParameters(Diags, D->
getBeginLoc())) {
3116 CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);
3119 shouldAnalyzeCalledOnceConventions(Diags, D->
getBeginLoc()));
3123 bool FallThroughDiagFull =
3125 bool FallThroughDiagPerFunction = !Diags.
isIgnored(
3126 diag::warn_unannotated_fallthrough_per_function, D->
getBeginLoc());
3127 if (FallThroughDiagFull || FallThroughDiagPerFunction ||
3132 if (S.getLangOpts().ObjCWeak &&
3138 if (!Diags.
isIgnored(diag::warn_infinite_recursive_function,
3140 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
3147 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
3153 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->
getBeginLoc())) {
3162 ++NumFunctionsAnalyzed;
3166 NumCFGBlocks += cfg->getNumBlockIDs();
3167 MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
3168 cfg->getNumBlockIDs());
3170 ++NumFunctionsWithBadCFGs;
3176 llvm::errs() <<
"\n*** Analysis Based Warnings Stats:\n";
3178 unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
3179 unsigned AvgCFGBlocksPerFunction =
3180 !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
3181 llvm::errs() << NumFunctionsAnalyzed <<
" functions analyzed ("
3182 << NumFunctionsWithBadCFGs <<
" w/o CFGs).\n"
3183 <<
" " << NumCFGBlocks <<
" CFG blocks built.\n"
3184 <<
" " << AvgCFGBlocksPerFunction
3185 <<
" average CFG blocks per function.\n"
3186 <<
" " << MaxCFGBlocksPerFunction
3187 <<
" max CFG blocks per function.\n";
3189 unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
3190 : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
3191 unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
3192 : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
3193 llvm::errs() << NumUninitAnalysisFunctions
3194 <<
" functions analyzed for uninitialiazed variables\n"
3195 <<
" " << NumUninitAnalysisVariables <<
" variables analyzed.\n"
3196 <<
" " << AvgUninitVariablesPerFunction
3197 <<
" average variables per function.\n"
3198 <<
" " << MaxUninitAnalysisVariablesPerFunction
3199 <<
" max variables per function.\n"
3200 <<
" " << NumUninitAnalysisBlockVisits <<
" block visits.\n"
3201 <<
" " << AvgUninitBlockVisitsPerFunction
3202 <<
" average block visits per function.\n"
3203 <<
" " << MaxUninitAnalysisBlockVisitsPerFunction
3204 <<
" 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 void emitPossiblyUnreachableDiags(Sema &S, AnalysisDeclContext &AC, std::pair< Iterator, Iterator > PUDs)
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)
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, ...);.
static bool ignoreUnsafeBufferInContainer(const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
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.
void registerForcedBlockExpression(const Stmt *stmt)
ParentMap & getParentMap()
const Decl * getDecl() const
bool getAddEHEdges() const
CFGReverseBlockReachabilityAnalysis * getCFGReachablityAnalysis()
ASTContext & getASTContext() const
CFG::BuildOptions & getCFGBuildOptions()
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,...
BinaryOperatorKind Opcode
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
ElementList::const_reverse_iterator const_reverse_iterator
FilteredCFGBlockIterator< const_pred_iterator, true > filtered_pred_iterator
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...
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...
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.
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]).
ExprIterator arg_iterator
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getBegin() const
ConditionalOperator - The ?
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 ?
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()
bool isFunctionOrMethod() const
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...
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.
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
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
const T * get() const
Retrieve the stored node as type T.
SourceRange getSourceRange(bool IncludeQualifier=false) const
For nodes which represent textual entities in the source code, return their SourceRange.
virtual bool TraverseDecl(MaybeConst< Decl > *D)
bool ShouldVisitTemplateInstantiations
bool ShouldVisitImplicitCode
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.
FunctionDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
bool doesThisDeclarationHaveABody() const
Returns whether this specific declaration of the function has a body.
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.
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
CXXMethodDecl * getCallOperator() const
Retrieve the function call operator associated with this lambda expression.
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>::".
@ Type
A type, stored as a Type*.
ObjCMethodDecl - Represents an instance or class method declaration.
bool hasBody() const override
Determine whether this method has a body.
Represents one property declaration in an Objective-C interface.
Stmt * getParent(Stmt *) const
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
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)
Emit a 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
SourceManager & getSourceManager() const
bool handlerCanCatch(QualType HandlerType, QualType ExceptionType)
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.
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
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>'.
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 isConstPtrUse() const
bool isConstRefOrPtrUse() const
bool isConstRefUse() 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.
The interface that lets the caller handle unsafe buffer usage analysis results by overriding this cla...
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 issueWarningsForRegisteredVarDecl(VarDecl *VD)
void IssueWarnings(Policy P, FunctionScopeInfo *fscope, const Decl *D, QualType BlockType)
void registerVarDeclWarning(VarDecl *VD, PossiblyUnreachableDiag PUD)
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.
bool HasFallthroughStmt
Whether there is a fallthrough statement in this function.
SmallVector< WeakUseTy, 4 > WeakUseVector
Used to collect uses of a particular weak object in a function body.
SmallVector< PossiblyUnreachableDiag, 4 > PossiblyUnreachableDiags
A list of PartialDiagnostics created but delayed within the current function scope.
llvm::SmallDenseMap< WeakObjectProfileTy, WeakUseVector, 8, WeakObjectProfileTy::DenseMapInfo > WeakObjectUseMap
Used to collect all uses of weak objects in a function body.
const WeakObjectUseMap & getWeakObjectUses() const
InterProceduralData aims to be a storage of whatever data should be passed between analyses of differ...
CalledOnceInterProceduralData CalledOnceData
std::list< DelayedDiag > DiagList
std::pair< PartialDiagnosticAt, OptionalNotes > DelayedDiag
SmallVector< PartialDiagnosticAt, 1 > OptionalNotes
uint32_t Variable
Boolean variables are represented as positive integers.
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.
AccessKind
This enum distinguishes between different ways to access (read or write) a variable.
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 isa(CodeGen::Address addr)
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)
bool hasSpecificAttr(const Container &container)
@ If
'if' clause, allowed on all the Compute Constructs, Data Constructs, Executable Constructs,...
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ 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.
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
A worklist implementation for backward dataflow analysis.
void enqueuePredecessors(const CFGBlock *Block)
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.
unsigned NumVariablesAnalyzed