51#include "llvm/ADT/ArrayRef.h"
52#include "llvm/ADT/BitVector.h"
53#include "llvm/ADT/DenseMap.h"
54#include "llvm/ADT/MapVector.h"
55#include "llvm/ADT/PostOrderIterator.h"
56#include "llvm/ADT/STLFunctionalExtras.h"
57#include "llvm/ADT/SmallVector.h"
58#include "llvm/ADT/StringExtras.h"
59#include "llvm/ADT/StringRef.h"
60#include "llvm/Support/Debug.h"
61#include "llvm/Support/TimeProfiler.h"
76 SourceRange PreviousSilenceableCondVal;
79 UnreachableCodeHandler(Sema &
s) : S(
s) {}
82 SourceRange SilenceableCondVal, SourceRange R1,
83 SourceRange R2,
bool HasFallThroughAttr)
override {
87 if (HasFallThroughAttr &&
88 !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr,
94 if (PreviousSilenceableCondVal.isValid() &&
96 PreviousSilenceableCondVal == SilenceableCondVal)
98 PreviousSilenceableCondVal = SilenceableCondVal;
100 unsigned diag = diag::warn_unreachable;
103 diag = diag::warn_unreachable_break;
106 diag = diag::warn_unreachable_return;
109 diag = diag::warn_unreachable_loop_increment;
115 S.Diag(L, diag) << R1 << R2;
118 if (
Open.isValid()) {
119 SourceLocation Close = SilenceableCondVal.
getEnd();
120 Close = S.getLocForEndOfToken(Close);
122 S.Diag(
Open, diag::note_unreachable_silence)
143 UnreachableCodeHandler UC(S);
153 LogicalErrorHandler(Sema &S) : S(S) {}
155 static bool HasMacroID(
const Expr *E) {
160 for (
const Stmt *SubStmt : E->
children())
161 if (
const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt))
162 if (HasMacroID(SubExpr))
168 void logicAlwaysTrue(
const BinaryOperator *B,
bool isAlwaysTrue)
override {
172 unsigned DiagID = isAlwaysTrue
173 ? diag::warn_tautological_negation_or_compare
174 : diag::warn_tautological_negation_and_compare;
179 void compareAlwaysTrue(
const BinaryOperator *B,
180 bool isAlwaysTrueOrFalse)
override {
185 S.Diag(B->
getExprLoc(), diag::warn_tautological_overlap_comparison)
186 << DiagRange << isAlwaysTrueOrFalse;
189 void compareBitwiseEquality(
const BinaryOperator *B,
190 bool isAlwaysTrue)
override {
195 S.Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_always)
196 << DiagRange << isAlwaysTrue;
199 void compareBitwiseOr(
const BinaryOperator *B)
override {
204 S.Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;
207 static bool hasActiveDiagnostics(DiagnosticsEngine &Diags,
208 SourceLocation Loc) {
209 return !Diags.
isIgnored(diag::warn_tautological_overlap_comparison, Loc) ||
210 !Diags.
isIgnored(diag::warn_comparison_bitwise_or, Loc) ||
211 !Diags.
isIgnored(diag::warn_tautological_negation_and_compare, Loc);
225 for (
const auto &B :
Block) {
239 if (isa_and_nonnull<TemplateSpecializationType>(NNS.getAsType()))
255 bool foundRecursion =
false;
260 WorkList.push_back(&cfg->
getEntry());
262 while (!WorkList.empty()) {
265 for (
auto I =
Block->succ_begin(), E =
Block->succ_end(); I != E; ++I) {
267 if (!Visited.insert(SuccBlock).second)
271 if (ExitID == SuccBlock->getBlockID())
276 foundRecursion =
true;
280 WorkList.push_back(SuccBlock);
284 return foundRecursion;
320 Stack.push_back(&ThrowBlock);
323 while (!Stack.empty()) {
324 CFGBlock &UnwindBlock = *Stack.pop_back_val();
326 for (
auto &Succ : UnwindBlock.
succs()) {
327 if (!Succ.isReachable() || Queued[Succ->getBlockID()])
334 dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
335 QualType Caught = Catch->getCaughtType();
342 Stack.push_back(Succ);
343 Queued[Succ->getBlockID()] =
true;
357 if (!Reachable[B->getBlockID()])
360 std::optional<CFGStmt> S = E.getAs<
CFGStmt>();
363 if (
auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))
373 S.
Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
379 getAs<FunctionProtoType>())
404 if (FPT->isNothrow() || FD->
hasAttr<NoThrowAttr>())
413 if (
auto *FD = dyn_cast<FunctionDecl>(DRef->getDecl()))
414 return FD->isNoReturn();
433struct TransferFunctions :
public StmtVisitor<TransferFunctions> {
435 std::optional<bool> AllValuesAreNoReturn;
437 TransferFunctions(
const VarDecl *VD) : Var(VD) {}
439 void reset() { AllValuesAreNoReturn = std::nullopt; }
441 void VisitDeclStmt(DeclStmt *DS) {
442 for (
auto *DI : DS->
decls())
443 if (
auto *VD = dyn_cast<VarDecl>(DI))
444 if (VarDecl *Def = VD->getDefinition())
449 void VisitUnaryOperator(UnaryOperator *UO) {
453 if (DRef->getDecl() == Var)
454 AllValuesAreNoReturn =
false;
458 void VisitBinaryOperator(BinaryOperator *BO) {
461 if (DRef->getDecl() == Var)
465 void VisitCallExpr(CallExpr *CE) {
468 const Expr *Arg = *I;
471 if (
auto VD = dyn_cast<VarDecl>(DRef->getDecl()))
472 if (VD->getDefinition() == Var)
473 AllValuesAreNoReturn =
false;
499 using MapTy = llvm::DenseMap<const CFGBlock *, std::optional<bool>>;
500 using ValueTy = MapTy::value_type;
502 BlocksToCheck[&VarBlk] = std::nullopt;
503 const auto BlockSatisfiesCondition = [](ValueTy Item) {
504 return Item.getSecond().value_or(
false);
507 TransferFunctions TF(VD);
509 llvm::DenseSet<const CFGBlock *> Visited;
512 if (Visited.contains(B))
518 if (std::optional<CFGStmt> cs = ri->getAs<
CFGStmt>()) {
519 const Stmt *S = cs->getStmt();
521 TF.Visit(
const_cast<Stmt *
>(S));
522 if (TF.AllValuesAreNoReturn) {
523 if (!TF.AllValuesAreNoReturn.value())
525 BlocksToCheck[B] =
true;
532 if (llvm::all_of(BlocksToCheck, BlockSatisfiesCondition))
537 if (!BlocksToCheck[B]) {
539 BlocksToCheck.erase(B);
540 for (
const auto &PredBlk : B->preds())
541 if (!BlocksToCheck.contains(PredBlk))
542 BlocksToCheck[PredBlk] = std::nullopt;
585 for (
const auto *B : *cfg) {
586 if (!live[B->getBlockID()]) {
587 if (B->preds().empty()) {
588 const Stmt *Term = B->getTerminatorStmt();
589 if (isa_and_nonnull<CXXTryStmt>(Term))
601 bool HasLiveReturn =
false;
602 bool HasFakeEdge =
false;
603 bool HasPlainEdge =
false;
604 bool HasAbnormalEdge =
false;
622 HasAbnormalEdge =
true;
631 for ( ; ri != re ; ++ri)
639 HasAbnormalEdge =
true;
650 HasLiveReturn =
true;
664 HasLiveReturn =
true;
668 HasAbnormalEdge =
true;
672 HasAbnormalEdge =
true;
675 if (
auto *
Call = dyn_cast<CallExpr>(S)) {
676 const Expr *Callee =
Call->getCallee();
677 if (Callee->getType()->isPointerType())
679 dyn_cast<DeclRefExpr>(Callee->IgnoreParenImpCasts()))
680 if (
auto *VD = dyn_cast<VarDecl>(DeclRef->getDecl()))
682 HasAbnormalEdge =
true;
694 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
704struct CheckFallThroughDiagnostics {
705 unsigned diag_FallThrough_HasNoReturn = 0;
706 unsigned diag_FallThrough_ReturnsNonVoid = 0;
707 unsigned diag_NeverFallThroughOrReturn = 0;
709 SourceLocation FuncLoc;
711 static CheckFallThroughDiagnostics MakeForFunction(Sema &S,
713 CheckFallThroughDiagnostics D;
714 D.FuncLoc =
Func->getLocation();
715 D.diag_FallThrough_HasNoReturn = diag::warn_noreturn_has_return_expr;
716 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
720 bool isVirtualMethod =
false;
721 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(
Func))
722 isVirtualMethod =
Method->isVirtual();
726 if (
const FunctionDecl *
Function = dyn_cast<FunctionDecl>(
Func)) {
730 D.diag_FallThrough_ReturnsNonVoid = diag::ext_main_no_return;
735 D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function;
737 D.FunKind = diag::FalloffFunctionKind::Function;
741 static CheckFallThroughDiagnostics MakeForCoroutine(
const Decl *
Func) {
742 CheckFallThroughDiagnostics D;
743 D.FuncLoc =
Func->getLocation();
744 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
745 D.FunKind = diag::FalloffFunctionKind::Coroutine;
749 static CheckFallThroughDiagnostics MakeForBlock() {
750 CheckFallThroughDiagnostics D;
751 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;
752 D.diag_FallThrough_ReturnsNonVoid = diag::err_falloff_nonvoid;
753 D.FunKind = diag::FalloffFunctionKind::Block;
757 static CheckFallThroughDiagnostics MakeForLambda() {
758 CheckFallThroughDiagnostics D;
759 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;
760 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
761 D.FunKind = diag::FalloffFunctionKind::Lambda;
765 bool checkDiagnostics(DiagnosticsEngine &D,
bool ReturnsVoid,
766 bool HasNoReturn)
const {
767 if (FunKind == diag::FalloffFunctionKind::Function) {
768 return (ReturnsVoid ||
769 D.
isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&
771 D.
isIgnored(diag::warn_noreturn_has_return_expr, FuncLoc)) &&
773 D.
isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));
775 if (FunKind == diag::FalloffFunctionKind::Coroutine) {
776 return (ReturnsVoid ||
777 D.
isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&
781 return ReturnsVoid && !HasNoReturn;
793 const CheckFallThroughDiagnostics &CD,
796 bool ReturnsVoid =
false;
797 bool HasNoReturn =
false;
799 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
800 if (
const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
801 ReturnsVoid = CBody->getFallthroughHandler() !=
nullptr;
803 ReturnsVoid = FD->getReturnType()->isVoidType();
804 HasNoReturn = FD->isNoReturn() || FD->hasAttr<InferredNoReturnAttr>();
806 else if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
807 ReturnsVoid = MD->getReturnType()->isVoidType();
808 HasNoReturn = MD->hasAttr<NoReturnAttr>();
813 if (FT->getReturnType()->isVoidType())
815 if (FT->getNoReturnAttr())
823 if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
839 if (CD.diag_FallThrough_HasNoReturn)
840 S.
Diag(RBrace, CD.diag_FallThrough_HasNoReturn) << CD.FunKind;
841 }
else if (!ReturnsVoid && CD.diag_FallThrough_ReturnsNonVoid) {
845 if (
const auto *CS = dyn_cast<CompoundStmt>(Body);
846 CS && !CS->body_empty()) {
847 const Stmt *LastStmt = CS->body_back();
849 if (
const auto *EWC = dyn_cast<ExprWithCleanups>(LastStmt)) {
850 LastStmt = EWC->getSubExpr();
852 if (
const auto *CE = dyn_cast<CallExpr>(LastStmt)) {
854 Callee && Callee->hasAttr<InferredNoReturnAttr>()) {
865 S.
Diag(RBrace, CD.diag_FallThrough_ReturnsNonVoid)
866 << CD.FunKind << NotInAllControlPaths;
870 if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
871 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
872 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
873 }
else if (
const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
874 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
876 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
895 const DeclRefExpr *Needle;
898 typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited;
900 ContainsReference(ASTContext &Context,
const DeclRefExpr *Needle)
901 : Inherited(Context), FoundReference(
false), Needle(Needle) {}
903 void VisitExpr(
const Expr *E) {
908 Inherited::VisitExpr(E);
911 void VisitDeclRefExpr(
const DeclRefExpr *E) {
913 FoundReference =
true;
918 bool doesContainReference()
const {
return FoundReference; }
926 S.
Diag(VD->
getLocation(), diag::note_block_var_fixit_add_initialization)
947 S.
Diag(Loc, diag::note_var_fixit_add_initialization) << VD->
getDeclName()
955 const Stmt *Else,
bool CondVal,
979 bool IsCapturedByBlock) {
980 bool Diagnosed =
false;
1012 const Stmt *Term = I->Terminator;
1022 int RemoveDiagKind = -1;
1023 const char *FixitStr =
1024 S.
getLangOpts().CPlusPlus ? (I->Output ?
"true" :
"false")
1025 : (I->Output ?
"1" :
"0");
1028 switch (Term ? Term->
getStmtClass() : Stmt::DeclStmtClass) {
1035 case Stmt::IfStmtClass: {
1042 I->Output, Fixit1, Fixit2);
1045 case Stmt::ConditionalOperatorClass: {
1052 I->Output, Fixit1, Fixit2);
1055 case Stmt::BinaryOperatorClass: {
1063 if ((BO->
getOpcode() == BO_LAnd && I->Output) ||
1064 (BO->
getOpcode() == BO_LOr && !I->Output))
1075 case Stmt::WhileStmtClass:
1082 case Stmt::ForStmtClass:
1092 case Stmt::CXXForRangeStmtClass:
1093 if (I->Output == 1) {
1105 case Stmt::DoStmtClass:
1108 Range =
cast<DoStmt>(Term)->getCond()->getSourceRange();
1114 case Stmt::CaseStmtClass:
1119 case Stmt::DefaultStmtClass:
1126 S.
Diag(Range.getBegin(), diag::warn_sometimes_uninit_var)
1127 << VD->
getDeclName() << IsCapturedByBlock << DiagKind
1128 << Str << I->Output << Range;
1131 if (RemoveDiagKind != -1)
1133 << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
1167 bool alwaysReportSelfInit =
false) {
1181 if (!alwaysReportSelfInit && DRE ==
Initializer->IgnoreParenImpCasts())
1184 ContainsReference CR(S.
Context, DRE);
1186 if (CR.doesContainReference()) {
1187 S.
Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
1198 diag::warn_uninit_byref_blockvar_captured_by_block)
1218 FallthroughMapper(Sema &S) : FoundSwitchStatements(
false), S(S) {
1219 ShouldWalkTypesOfTypeLocs =
false;
1222 bool foundSwitchStatements()
const {
return FoundSwitchStatements; }
1224 void markFallthroughVisited(
const AttributedStmt *Stmt) {
1225 bool Found = FallthroughStmts.erase(Stmt);
1230 typedef llvm::SmallPtrSet<const AttributedStmt *, 8> AttrStmts;
1232 const AttrStmts &getFallthroughStmts()
const {
return FallthroughStmts; }
1234 void fillReachableBlocks(CFG *Cfg) {
1235 assert(ReachableBlocks.empty() &&
"ReachableBlocks already filled");
1236 std::deque<const CFGBlock *> BlockQueue;
1238 ReachableBlocks.insert(&Cfg->
getEntry());
1239 BlockQueue.push_back(&Cfg->
getEntry());
1244 for (
const auto *B : *Cfg) {
1245 const Stmt *L = B->getLabel();
1246 if (isa_and_nonnull<SwitchCase>(L) && ReachableBlocks.insert(B).second)
1247 BlockQueue.push_back(B);
1250 while (!BlockQueue.empty()) {
1251 const CFGBlock *P = BlockQueue.front();
1252 BlockQueue.pop_front();
1253 for (
const CFGBlock *B : P->
succs()) {
1254 if (B && ReachableBlocks.insert(B).second)
1255 BlockQueue.push_back(B);
1260 bool checkFallThroughIntoBlock(
const CFGBlock &B,
int &AnnotatedCnt,
1261 bool IsTemplateInstantiation) {
1262 assert(!ReachableBlocks.empty() &&
"ReachableBlocks empty");
1264 int UnannotatedCnt = 0;
1268 while (!BlockQueue.empty()) {
1269 const CFGBlock *P = BlockQueue.
front();
1270 BlockQueue.pop_front();
1275 if (isa_and_nonnull<SwitchStmt>(Term))
1278 const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->
getLabel());
1282 const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->
getLabel());
1286 if (!ReachableBlocks.count(P)) {
1287 for (
const CFGElement &Elem : llvm::reverse(*P)) {
1288 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) {
1289 if (
const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
1293 if (!IsTemplateInstantiation)
1294 S.Diag(AS->getBeginLoc(),
1295 diag::warn_unreachable_fallthrough_attr);
1296 markFallthroughVisited(AS);
1315 if (
const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {
1316 markFallthroughVisited(AS);
1324 std::back_inserter(BlockQueue));
1330 return !!UnannotatedCnt;
1333 bool VisitAttributedStmt(AttributedStmt *S)
override {
1334 if (asFallThroughAttr(S))
1335 FallthroughStmts.insert(S);
1339 bool VisitSwitchStmt(SwitchStmt *S)
override {
1340 FoundSwitchStatements =
true;
1346 bool TraverseDecl(Decl *D)
override {
return true; }
1349 bool TraverseLambdaExpr(
LambdaExpr *LE)
override {
1351 for (
const auto C : zip(
LE->captures(),
LE->capture_inits()))
1352 TraverseLambdaCapture(LE, &std::get<0>(
C), std::get<1>(
C));
1358 static const AttributedStmt *asFallThroughAttr(
const Stmt *S) {
1359 if (
const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
1366 static const Stmt *
getLastStmt(
const CFGBlock &B) {
1369 for (
const CFGElement &Elem : llvm::reverse(B))
1370 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
1371 return CS->getStmt();
1375 if (
const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.
getLabel()))
1382 bool FoundSwitchStatements;
1383 AttrStmts FallthroughStmts;
1385 llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
1392 tok::l_square, tok::l_square,
1394 tok::r_square, tok::r_square
1400 tok::r_square, tok::r_square
1405 StringRef MacroName;
1406 if (PreferClangAttr)
1408 if (MacroName.empty())
1410 if (MacroName.empty() && !PreferClangAttr)
1412 if (MacroName.empty()) {
1413 if (!PreferClangAttr)
1414 MacroName =
"[[fallthrough]]";
1416 MacroName =
"[[clang::fallthrough]]";
1418 MacroName =
"__attribute__((fallthrough))";
1425 FallthroughMapper FM(S);
1426 FM.TraverseStmt(AC.
getBody());
1428 if (!FM.foundSwitchStatements())
1431 if (PerFunction && FM.getFallthroughStmts().empty())
1439 FM.fillReachableBlocks(Cfg);
1441 for (
const CFGBlock *B : llvm::reverse(*Cfg)) {
1444 if (!isa_and_nonnull<SwitchCase>(Label))
1449 bool IsTemplateInstantiation =
false;
1451 IsTemplateInstantiation = Function->isTemplateInstantiation();
1452 if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,
1453 IsTemplateInstantiation))
1457 PerFunction ? diag::warn_unannotated_fallthrough_per_function
1458 : diag::warn_unannotated_fallthrough);
1460 if (!AnnotatedCnt) {
1471 if (!(B->
empty() && isa_and_nonnull<BreakStmt>(Term))) {
1475 TextToInsert +=
"; ";
1476 S.
Diag(L, diag::note_insert_fallthrough_fixit)
1477 << AnnotationSpelling
1480 S.
Diag(L, diag::note_insert_break_fixit)
1485 for (
const auto *F : FM.getFallthroughStmts())
1486 S.
Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement);
1495 case Stmt::ForStmtClass:
1496 case Stmt::WhileStmtClass:
1497 case Stmt::CXXForRangeStmtClass:
1498 case Stmt::ObjCForCollectionStmtClass:
1500 case Stmt::DoStmtClass: {
1504 return Result.
Val.
getInt().getBoolValue();
1521 typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
1530 for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end();
1532 const WeakUseVector &Uses = I->second;
1535 WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
1536 for ( ; UI != UE; ++UI) {
1549 if (UI == Uses.begin()) {
1550 WeakUseVector::const_iterator UI2 = UI;
1551 for (++UI2; UI2 != UE; ++UI2)
1552 if (UI2->isUnsafe())
1556 if (!
isInLoop(Ctx, PM, UI->getUseExpr()))
1559 const WeakObjectProfileTy &Profile = I->first;
1560 if (!Profile.isExactProfile())
1565 Base = Profile.getProperty();
1566 assert(
Base &&
"A profile always has a base or property.");
1568 if (
const VarDecl *BaseVar = dyn_cast<VarDecl>(
Base))
1574 UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
1577 if (UsesByStmt.empty())
1582 llvm::sort(UsesByStmt,
1583 [&
SM](
const StmtUsesPair &LHS,
const StmtUsesPair &RHS) {
1584 return SM.isBeforeInTranslationUnit(LHS.first->getBeginLoc(),
1585 RHS.first->getBeginLoc());
1601 FunctionKind =
Block;
1603 FunctionKind = Lambda;
1605 FunctionKind = Method;
1607 FunctionKind = Function;
1610 for (
const auto &P : UsesByStmt) {
1611 const Stmt *FirstRead = P.first;
1612 const WeakObjectProfileTy &Key = P.second->first;
1613 const WeakUseVector &Uses = P.second->second;
1621 if (Key.isExactProfile())
1622 DiagKind = diag::warn_arc_repeated_use_of_weak;
1624 DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
1636 const NamedDecl *KeyProp = Key.getProperty();
1638 ObjectKind = Variable;
1640 ObjectKind = Property;
1642 ObjectKind = ImplicitProperty;
1646 llvm_unreachable(
"Unexpected weak object kind!");
1651 if (Prop->hasAttr<IBOutletAttr>())
1656 <<
int(ObjectKind) << KeyProp <<
int(FunctionKind)
1660 for (
const auto &Use : Uses) {
1661 if (Use.getUseExpr() == FirstRead)
1663 S.
Diag(Use.getUseExpr()->getBeginLoc(),
1664 diag::note_arc_weak_also_accessed_here)
1665 << Use.getUseExpr()->getSourceRange();
1673typedef std::pair<PartialDiagnosticAt, OptionalNotes>
DelayedDiag;
1674typedef std::list<DelayedDiag>
DiagList;
1676struct SortDiagBySourceLocation {
1678 SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {}
1680 bool operator()(
const DelayedDiag &left,
const DelayedDiag &right) {
1683 return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
1692 typedef SmallVector<UninitUse, 2> UsesVec;
1693 typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
1697 typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
1701 UninitValsDiagReporter(Sema &S) : S(S) {}
1704 MappedType &getUses(
const VarDecl *vd) {
1705 MappedType &
V = uses[vd];
1706 if (!
V.getPointer())
1707 V.setPointer(
new UsesVec());
1711 void handleUseOfUninitVariable(
const VarDecl *vd,
1712 const UninitUse &use)
override {
1713 getUses(vd).getPointer()->push_back(use);
1716 void handleSelfInit(
const VarDecl *vd)
override { getUses(vd).setInt(
true); }
1719 for (
const auto &P : uses) {
1720 const VarDecl *vd = P.first;
1721 const MappedType &
V = P.second;
1723 UsesVec *vec =
V.getPointer();
1724 bool hasSelfInit =
V.getInt();
1726 diagnoseUnitializedVar(vd, hasSelfInit, vec);
1736 static bool hasAlwaysUninitializedUse(
const UsesVec* vec) {
1737 return llvm::any_of(*vec, [](
const UninitUse &U) {
1747 void diagnoseUnitializedVar(
const VarDecl *vd,
bool hasSelfInit,
1752 if (hasSelfInit && hasAlwaysUninitializedUse(vec)) {
1763 llvm::sort(*vec, [](
const UninitUse &a,
const UninitUse &
b) {
1767 return b.isConstRefOrPtrUse();
1774 for (
const auto &U : *vec) {
1783 UninitUse Use = hasSelfInit ? UninitUse(U.
getUser(),
false) : U;
1792class CalledOnceInterProceduralData {
1795 void addDelayedWarning(
const BlockDecl *
Block,
1797 DelayedBlockWarnings[
Block].emplace_back(std::move(
Warning));
1800 void flushWarnings(
const BlockDecl *
Block, Sema &S) {
1802 S.
Diag(Delayed.first, Delayed.second);
1804 discardWarnings(
Block);
1807 void discardWarnings(
const BlockDecl *
Block) {
1808 DelayedBlockWarnings.erase(
Block);
1812 using DelayedDiagnostics = SmallVector<PartialDiagnosticAt, 2>;
1813 llvm::DenseMap<const BlockDecl *, DelayedDiagnostics> DelayedBlockWarnings;
1818 CalledOnceCheckReporter(Sema &S, CalledOnceInterProceduralData &Data)
1819 : S(S), Data(Data) {}
1820 void handleDoubleCall(
const ParmVarDecl *
Parameter,
const Expr *
Call,
1821 const Expr *PrevCall,
bool IsCompletionHandler,
1822 bool Poised)
override {
1823 auto DiagToReport = IsCompletionHandler
1824 ? diag::warn_completion_handler_called_twice
1825 : diag::warn_called_once_gets_called_twice;
1827 S.Diag(PrevCall->
getBeginLoc(), diag::note_called_once_gets_called_twice)
1831 void handleNeverCalled(
const ParmVarDecl *
Parameter,
1832 bool IsCompletionHandler)
override {
1833 auto DiagToReport = IsCompletionHandler
1834 ? diag::warn_completion_handler_never_called
1835 : diag::warn_called_once_never_called;
1836 S.Diag(
Parameter->getBeginLoc(), DiagToReport)
1842 bool IsCalledDirectly,
1843 bool IsCompletionHandler)
override {
1844 auto DiagToReport = IsCompletionHandler
1845 ? diag::warn_completion_handler_never_called_when
1846 : diag::warn_called_once_never_called_when;
1850 << (
unsigned)Reason);
1860 void handleCapturedNeverCalled(
const ParmVarDecl *
Parameter,
1862 bool IsCompletionHandler)
override {
1863 auto DiagToReport = IsCompletionHandler
1864 ? diag::warn_completion_handler_never_called
1865 : diag::warn_called_once_never_called;
1871 handleBlockThatIsGuaranteedToBeCalledOnce(
const BlockDecl *
Block)
override {
1872 Data.flushWarnings(
Block, S);
1875 void handleBlockWithNoGuarantees(
const BlockDecl *
Block)
override {
1876 Data.discardWarnings(
Block);
1881 CalledOnceInterProceduralData &Data;
1884constexpr unsigned CalledOnceWarnings[] = {
1885 diag::warn_called_once_never_called,
1886 diag::warn_called_once_never_called_when,
1887 diag::warn_called_once_gets_called_twice};
1889constexpr unsigned CompletionHandlerWarnings[]{
1890 diag::warn_completion_handler_never_called,
1891 diag::warn_completion_handler_never_called_when,
1892 diag::warn_completion_handler_called_twice};
1897 return llvm::any_of(DiagIDs, [&Diags, At](
unsigned DiagID) {
1904 return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);
1909 return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||
1910 shouldAnalyzeCalledOnceConventions(Diags, At);
1920class ThreadSafetyReporter :
public clang::threadSafety::ThreadSafetyHandler {
1923 SourceLocation FunLocation, FunEndLocation;
1925 const FunctionDecl *CurrentFunction;
1929 if (Verbose && CurrentFunction) {
1931 S.PDiag(diag::note_thread_warning_in_fun)
1932 << CurrentFunction);
1940 if (Verbose && CurrentFunction) {
1942 S.PDiag(diag::note_thread_warning_in_fun)
1943 << CurrentFunction);
1944 ONS.push_back(std::move(FNote));
1952 ONS.push_back(Note1);
1953 ONS.push_back(Note2);
1954 if (Verbose && CurrentFunction) {
1956 S.PDiag(diag::note_thread_warning_in_fun)
1957 << CurrentFunction);
1958 ONS.push_back(std::move(FNote));
1963 OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) {
1966 LocLocked, S.PDiag(diag::note_locked_here) << Kind))
1970 OptionalNotes makeUnlockedHereNote(SourceLocation LocUnlocked,
1974 LocUnlocked, S.PDiag(diag::note_unlocked_here) << Kind))
1978 OptionalNotes makeManagedMismatchNoteForParam(SourceLocation DeclLoc) {
1982 S.PDiag(diag::note_managed_mismatch_here_for_param)))
1987 ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
1988 : S(S), FunLocation(FL), FunEndLocation(FEL),
1991 void setVerbose(
bool b) { Verbose =
b; }
1998 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
1999 for (
const auto &
Diag : Warnings) {
2000 S.Diag(
Diag.first.first,
Diag.first.second);
2001 for (
const auto &
Note :
Diag.second)
2006 void handleUnmatchedUnderlyingMutexes(SourceLocation Loc, SourceLocation DLoc,
2007 Name scopeName, StringRef Kind,
2008 Name expected, Name actual)
override {
2010 S.PDiag(diag::warn_unmatched_underlying_mutexes)
2011 << Kind << scopeName << expected << actual);
2012 Warnings.emplace_back(std::move(
Warning),
2013 makeManagedMismatchNoteForParam(DLoc));
2016 void handleExpectMoreUnderlyingMutexes(SourceLocation Loc,
2017 SourceLocation DLoc, Name scopeName,
2019 Name expected)
override {
2021 Loc, S.PDiag(diag::warn_expect_more_underlying_mutexes)
2022 << Kind << scopeName << expected);
2023 Warnings.emplace_back(std::move(
Warning),
2024 makeManagedMismatchNoteForParam(DLoc));
2027 void handleExpectFewerUnderlyingMutexes(SourceLocation Loc,
2028 SourceLocation DLoc, Name scopeName,
2030 Name actual)
override {
2032 Loc, S.PDiag(diag::warn_expect_fewer_underlying_mutexes)
2033 << Kind << scopeName << actual);
2034 Warnings.emplace_back(std::move(
Warning),
2035 makeManagedMismatchNoteForParam(DLoc));
2038 void handleInvalidLockExp(SourceLocation Loc)
override {
2041 Warnings.emplace_back(std::move(
Warning), getNotes());
2044 void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc,
2045 SourceLocation LocPreviousUnlock)
override {
2049 << Kind << LockName);
2050 Warnings.emplace_back(std::move(
Warning),
2051 makeUnlockedHereNote(LocPreviousUnlock, Kind));
2054 void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
2056 SourceLocation LocLocked,
2057 SourceLocation LocUnlock)
override {
2059 LocUnlock = FunLocation;
2061 LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch)
2062 << Kind << LockName << Received << Expected);
2063 Warnings.emplace_back(std::move(
Warning),
2064 makeLockedHereNote(LocLocked, Kind));
2067 void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked,
2068 SourceLocation LocDoubleLock)
override {
2070 LocDoubleLock = FunLocation;
2072 << Kind << LockName);
2073 Warnings.emplace_back(std::move(
Warning),
2074 makeLockedHereNote(LocLocked, Kind));
2077 void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
2078 SourceLocation LocLocked,
2079 SourceLocation LocEndOfScope,
2081 bool ReentrancyMismatch)
override {
2082 unsigned DiagID = 0;
2085 DiagID = diag::warn_lock_some_predecessors;
2088 DiagID = diag::warn_expecting_lock_held_on_loop;
2091 DiagID = diag::warn_no_unlock;
2094 DiagID = diag::warn_expecting_locked;
2098 LocEndOfScope = FunEndLocation;
2102 << ReentrancyMismatch);
2103 Warnings.emplace_back(std::move(
Warning),
2104 makeLockedHereNote(LocLocked, Kind));
2107 void handleExclusiveAndShared(StringRef Kind, Name LockName,
2108 SourceLocation Loc1,
2109 SourceLocation Loc2)
override {
2111 S.PDiag(diag::warn_lock_exclusive_and_shared)
2112 << Kind << LockName);
2114 << Kind << LockName);
2115 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2119 AccessKind AK, SourceLocation Loc)
override {
2120 unsigned DiagID = 0;
2127 DiagID = diag::warn_variable_requires_any_lock;
2134 DiagID = diag::warn_var_deref_requires_any_lock;
2137 llvm_unreachable(
"Only works for variables");
2142 Warnings.emplace_back(std::move(
Warning), getNotes());
2145 void handleGuardedByAnyReadNotHeld(
const NamedDecl *D,
2147 ArrayRef<StringRef> LockNames,
2148 SourceLocation Loc)
override {
2166 llvm_unreachable(
"POK_FunctionCall not applicable here");
2169 llvm::raw_string_ostream
OS(Quoted);
2170 llvm::ListSeparator LS;
2171 for (StringRef Name : LockNames)
2172 OS << LS <<
"'" << Name <<
"'";
2174 << D << IsDeref << Quoted);
2175 Warnings.emplace_back(std::move(
Warning), getNotes());
2178 void handleMutexNotHeld(StringRef Kind,
const NamedDecl *D,
2181 Name *PossibleMatch)
override {
2182 unsigned DiagID = 0;
2183 if (PossibleMatch) {
2186 DiagID = diag::warn_variable_requires_lock_precise;
2189 DiagID = diag::warn_var_deref_requires_lock_precise;
2192 DiagID = diag::warn_fun_requires_lock_precise;
2195 DiagID = diag::warn_guarded_pass_by_reference;
2198 DiagID = diag::warn_pt_guarded_pass_by_reference;
2201 DiagID = diag::warn_guarded_return_by_reference;
2204 DiagID = diag::warn_pt_guarded_return_by_reference;
2207 DiagID = diag::warn_guarded_pass_pointer;
2210 DiagID = diag::warn_pt_guarded_pass_pointer;
2213 DiagID = diag::warn_guarded_return_pointer;
2216 DiagID = diag::warn_pt_guarded_return_pointer;
2226 S.PDiag(diag::note_guarded_by_declared_here)
2228 Warnings.emplace_back(std::move(
Warning), getNotes(
Note, VNote));
2230 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2234 DiagID = diag::warn_variable_requires_lock;
2237 DiagID = diag::warn_var_deref_requires_lock;
2240 DiagID = diag::warn_fun_requires_lock;
2243 DiagID = diag::warn_guarded_pass_by_reference;
2246 DiagID = diag::warn_pt_guarded_pass_by_reference;
2249 DiagID = diag::warn_guarded_return_by_reference;
2252 DiagID = diag::warn_pt_guarded_return_by_reference;
2255 DiagID = diag::warn_guarded_pass_pointer;
2258 DiagID = diag::warn_pt_guarded_pass_pointer;
2261 DiagID = diag::warn_guarded_return_pointer;
2264 DiagID = diag::warn_pt_guarded_return_pointer;
2272 S.PDiag(diag::note_guarded_by_declared_here));
2273 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2275 Warnings.emplace_back(std::move(
Warning), getNotes());
2279 void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
2280 SourceLocation Loc)
override {
2282 S.PDiag(diag::warn_acquire_requires_negative_cap)
2283 << Kind << LockName << Neg);
2284 Warnings.emplace_back(std::move(
Warning), getNotes());
2287 void handleNegativeNotHeld(
const NamedDecl *D, Name LockName,
2288 SourceLocation Loc)
override {
2290 Loc, S.PDiag(diag::warn_fun_requires_negative_cap) << D << LockName);
2291 Warnings.emplace_back(std::move(
Warning), getNotes());
2294 void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
2295 SourceLocation Loc)
override {
2297 << Kind << FunName << LockName);
2298 Warnings.emplace_back(std::move(
Warning), getNotes());
2301 void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
2302 SourceLocation Loc)
override {
2304 S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
2305 Warnings.emplace_back(std::move(
Warning), getNotes());
2308 void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc)
override {
2310 S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
2311 Warnings.emplace_back(std::move(
Warning), getNotes());
2314 void enterFunction(
const FunctionDecl* FD)
override {
2315 CurrentFunction = FD;
2318 void leaveFunction(
const FunctionDecl* FD)
override {
2319 CurrentFunction =
nullptr;
2340 ConsumedWarningsHandler(Sema &S) : S(S) {}
2343 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
2344 for (
const auto &
Diag : Warnings) {
2345 S.Diag(
Diag.first.first,
Diag.first.second);
2346 for (
const auto &
Note :
Diag.second)
2351 void warnLoopStateMismatch(SourceLocation Loc,
2352 StringRef VariableName)
override {
2359 void warnParamReturnTypestateMismatch(SourceLocation Loc,
2360 StringRef VariableName,
2361 StringRef ExpectedState,
2362 StringRef ObservedState)
override {
2365 diag::warn_param_return_typestate_mismatch) << VariableName <<
2366 ExpectedState << ObservedState);
2371 void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
2372 StringRef ObservedState)
override {
2375 diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
2380 void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
2381 StringRef TypeName)
override {
2383 diag::warn_return_typestate_for_unconsumable_type) << TypeName);
2388 void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
2389 StringRef ObservedState)
override {
2392 diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
2397 void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
2398 SourceLocation Loc)
override {
2401 diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
2406 void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
2407 StringRef State, SourceLocation Loc)
override {
2410 MethodName << VariableName << State);
2426 bool SuggestSuggestions;
2430 std::string listVariableGroupAsString(
2431 const VarDecl *VD,
const ArrayRef<const VarDecl *> &VarGroupForVD)
const {
2432 if (VarGroupForVD.size() <= 1)
2435 std::vector<StringRef> VarNames;
2436 auto PutInQuotes = [](StringRef S) -> std::string {
2437 return "'" + S.str() +
"'";
2440 for (
auto *
V : VarGroupForVD) {
2443 VarNames.push_back(
V->getName());
2445 if (VarNames.size() == 1) {
2446 return PutInQuotes(VarNames[0]);
2448 if (VarNames.size() == 2) {
2449 return PutInQuotes(VarNames[0]) +
" and " + PutInQuotes(VarNames[1]);
2451 assert(VarGroupForVD.size() > 3);
2452 const unsigned N = VarNames.size() -
2454 std::string AllVars =
"";
2456 for (
unsigned I = 0; I < N; ++I)
2457 AllVars.append(PutInQuotes(VarNames[I]) +
", ");
2458 AllVars.append(PutInQuotes(VarNames[N]) +
", and " +
2459 PutInQuotes(VarNames[N + 1]));
2464 UnsafeBufferUsageReporter(Sema &S,
bool SuggestSuggestions)
2465 : S(S), SuggestSuggestions(SuggestSuggestions) {}
2467 void handleUnsafeOperation(
const Stmt *Operation,
bool IsRelatedToDecl,
2468 ASTContext &Ctx)
override {
2471 unsigned MsgParam = 0;
2472 NamedDecl *D =
nullptr;
2473 if (
const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
2474 Loc = ASE->getBase()->getExprLoc();
2475 Range = ASE->getBase()->getSourceRange();
2477 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
2479 if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
2480 Op == BO_SubAssign) {
2490 }
else if (
const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
2492 if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
2501 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2505 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2507 D = ME->getMemberDecl();
2509 }
else if (
const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) {
2510 QualType destType = ECE->getType();
2511 bool destTypeComplete =
true;
2517 destTypeComplete = D->isCompleteDefinition();
2521 if (destTypeComplete) {
2523 QualType srcType = ECE->getSubExpr()->getType();
2533 if (
const auto *CE = dyn_cast<CXXMemberCallExpr>(
2534 ECE->getSubExpr()->IgnoreParens())) {
2535 D = CE->getMethodDecl();
2546 if (IsRelatedToDecl) {
2547 assert(!SuggestSuggestions &&
2548 "Variables blamed for unsafe buffer usage without suggestions!");
2549 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2552 S.Diag(Loc, diag::warn_unsafe_buffer_operation)
2553 << MsgParam << D <<
Range;
2555 S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam <<
Range;
2557 if (SuggestSuggestions) {
2558 S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled);
2563 void handleUnsafeLibcCall(
const CallExpr *
Call,
unsigned PrintfInfo,
2565 const Expr *UnsafeArg =
nullptr)
override {
2566 unsigned DiagID = diag::warn_unsafe_buffer_libc_call;
2567 if (PrintfInfo & 0x8) {
2571 DiagID = diag::warn_unsafe_buffer_format_attr_call;
2574 S.Diag(
Call->getBeginLoc(), DiagID)
2575 <<
Call->getDirectCallee()
2576 <<
Call->getSourceRange();
2577 if (PrintfInfo > 0) {
2579 UnsafeArg ? UnsafeArg->getSourceRange() :
Call->getSourceRange();
2580 S.Diag(
R.getBegin(), diag::note_unsafe_buffer_printf_call)
2585 void handleUnsafeOperationInContainer(
const Stmt *Operation,
2586 bool IsRelatedToDecl,
2587 ASTContext &Ctx)
override {
2590 unsigned MsgParam = 0;
2595 Loc = CtorExpr->getLocation();
2597 S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container);
2598 if (IsRelatedToDecl) {
2599 assert(!SuggestSuggestions &&
2600 "Variables blamed for unsafe buffer usage without suggestions!");
2601 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2605 void handleUnsafeVariableGroup(
const VarDecl *Variable,
2606 const VariableGroupsManager &VarGrpMgr,
2607 FixItList &&Fixes,
const Decl *D,
2608 const FixitStrategy &VarTargetTypes)
override {
2609 assert(!SuggestSuggestions &&
2610 "Unsafe buffer usage fixits displayed without suggestions!");
2611 S.Diag(
Variable->getLocation(), diag::warn_unsafe_buffer_variable)
2614 if (!Fixes.empty()) {
2616 "Fix-its are generated only for `NamedDecl`s");
2618 bool BriefMsg =
false;
2622 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Variable, &BriefMsg);
2623 unsigned FixItStrategy = 0;
2624 switch (VarTargetTypes.
lookup(Variable)) {
2632 assert(
false &&
"We support only std::span and std::array");
2637 BriefMsg ? diag::note_unsafe_buffer_variable_fixit_together
2638 : diag::note_unsafe_buffer_variable_fixit_group);
2641 FD << listVariableGroupAsString(Variable, VarGroupForVD)
2642 << (VarGroupForVD.size() > 1) << ND;
2643 for (
const auto &F : Fixes) {
2649 if (areDebugNotesRequested())
2650 for (
const DebugNote &
Note: DebugNotesByVar[Variable])
2651 S.Diag(
Note.first, diag::note_safe_buffer_debug_mode) <<
Note.second;
2655 void handleUnsafeUniquePtrArrayAccess(
const DynTypedNode &Node,
2656 bool IsRelatedToDecl,
2657 ASTContext &Ctx)
override {
2660 Loc = Node.
get<Stmt>()->getBeginLoc();
2661 S.Diag(Loc, diag::warn_unsafe_buffer_usage_unique_ptr_array_access)
2665 bool isSafeBufferOptOut(
const SourceLocation &Loc)
const override {
2666 return S.PP.isSafeBufferOptOut(S.getSourceManager(), Loc);
2670 return S.Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container, Loc);
2673 bool ignoreUnsafeBufferInLibcCall(
const SourceLocation &Loc)
const override {
2674 return S.Diags.isIgnored(diag::warn_unsafe_buffer_libc_call, Loc);
2677 bool ignoreUnsafeBufferInStaticSizedArray(
2678 const SourceLocation &Loc)
const override {
2679 return S.Diags.isIgnored(
2680 diag::warn_unsafe_buffer_usage_in_static_sized_array, Loc);
2687 getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,
2688 StringRef WSSuffix =
"")
const override {
2689 Preprocessor &PP = S.getPreprocessor();
2690 TokenValue ClangUnsafeBufferUsageTokens[] = {
2699 StringRef MacroName;
2703 if (MacroName.empty())
2704 MacroName =
"[[clang::unsafe_buffer_usage]]";
2705 return MacroName.str() + WSSuffix.str();
2716 enableCheckFallThrough = 1;
2717 enableCheckUnreachable = 0;
2718 enableThreadSafetyAnalysis = 0;
2719 enableConsumedAnalysis = 0;
2740template <
typename... Ts>
2743 return (!D.
isIgnored(Diags, Loc) || ...);
2748 NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),
2749 MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),
2750 NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
2751 NumUninitAnalysisBlockVisits(0),
2752 MaxUninitAnalysisBlockVisitsPerFunction(0) {
2760 using namespace diag;
2766 P.enableCheckUnreachable =
2767 PolicyOverrides.enableCheckUnreachable ||
2768 areAnyEnabled(D, Loc, warn_unreachable, warn_unreachable_break,
2769 warn_unreachable_return, warn_unreachable_loop_increment);
2771 P.enableThreadSafetyAnalysis = PolicyOverrides.enableThreadSafetyAnalysis ||
2774 P.enableConsumedAnalysis = PolicyOverrides.enableConsumedAnalysis ||
2779void sema::AnalysisBasedWarnings::clearOverrides() {
2780 PolicyOverrides.enableCheckUnreachable =
false;
2781 PolicyOverrides.enableConsumedAnalysis =
false;
2782 PolicyOverrides.enableThreadSafetyAnalysis =
false;
2787 S.
Diag(D.Loc, D.PD);
2790template <
typename Iterator>
2792 std::pair<Iterator, Iterator> PUDs) {
2794 if (PUDs.first == PUDs.second)
2797 for (
auto I = PUDs.first; I != PUDs.second; ++I) {
2798 for (
const Stmt *S : I->Stmts)
2806 for (
auto I = PUDs.first; I != PUDs.second; ++I) {
2808 if (llvm::all_of(D.Stmts, [&](
const Stmt *St) {
2809 const CFGBlock *Block = AC.getBlockForRegisteredExpression(St);
2813 if (Block && Analysis)
2814 if (!Analysis->isReachable(&AC.getCFG()->getEntry(), Block))
2818 S.
Diag(D.Loc, D.PD);
2822 for (
auto I = PUDs.first; I != PUDs.second; ++I)
2823 S.
Diag(I->Loc, I->PD);
2829 VarDeclPossiblyUnreachableDiags.emplace(VD, PUD);
2834 if (!llvm::is_contained(VarDeclPossiblyUnreachableDiags, VD))
2847 auto Range = VarDeclPossiblyUnreachableDiags.equal_range(VD);
2849 llvm::make_second_range(llvm::make_range(Range.first, Range.second));
2851 S, AC, std::make_pair(SecondRange.begin(), SecondRange.end()));
2858 llvm::function_ref<void(
const Decl *)> Callback;
2859 const Module *
const TUModule;
2863 const Module *
const TUModule)
2864 : Callback(Callback), TUModule(TUModule) {
2912 llvm::TimeTraceScope TimeProfile(
"LifetimeSafetyTUAnalysis");
2916 for (
auto *Node : llvm::post_order(&CG)) {
2918 dyn_cast_or_null<clang::FunctionDecl>(Node->getDecl());
2930 runLifetimeSafetyAnalysis(AC, &SemaHelper, LSStats, S.
CollectStats);
2948 bool UnsafeBufferUsageCanEmitSuggestions = S.getLangOpts().CPlusPlus20;
2949 bool UnsafeBufferUsageShouldEmitSuggestions =
2950 UnsafeBufferUsageCanEmitSuggestions &&
2951 DiagOpts.ShowSafeBufferUsageSuggestions;
2952 bool UnsafeBufferUsageShouldSuggestSuggestions =
2953 UnsafeBufferUsageCanEmitSuggestions &&
2954 !DiagOpts.ShowSafeBufferUsageSuggestions;
2955 UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions);
2958 auto CallAnalyzers = [&](
const Decl *Node) ->
void {
2959 if (Node->hasAttr<UnsafeBufferUsageAttr>())
2963 if (!Diags.
isIgnored(diag::warn_unsafe_buffer_operation,
2964 Node->getBeginLoc()) ||
2965 !Diags.
isIgnored(diag::warn_unsafe_buffer_variable,
2966 Node->getBeginLoc()) ||
2967 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2968 Node->getBeginLoc()) ||
2969 !Diags.
isIgnored(diag::warn_unsafe_buffer_libc_call,
2970 Node->getBeginLoc())) {
2972 UnsafeBufferUsageShouldEmitSuggestions);
2981 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2984 S.getLangOpts().CPlusPlus )) {
2986 .TraverseTranslationUnitDecl(TU);
2989 if (S.getLangOpts().EnableLifetimeSafety && S.getLangOpts().CPlusPlus &&
2990 S.getLangOpts().EnableLifetimeSafetyTUAnalysis)
3016 if (S.hasUncompilableErrorOccurred()) {
3039 bool EnableLifetimeSafetyAnalysis =
3040 S.getLangOpts().EnableLifetimeSafety &&
3041 !S.getLangOpts().EnableLifetimeSafetyTUAnalysis &&
3050 if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||
3051 P.enableConsumedAnalysis || EnableLifetimeSafetyAnalysis) {
3064 if (EnableLifetimeSafetyAnalysis)
3068 std::optional<LogicalErrorHandler> LEH;
3069 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->
getBeginLoc())) {
3079 if (P.enableCheckFallThrough) {
3080 const CheckFallThroughDiagnostics &CD =
3085 ? CheckFallThroughDiagnostics::MakeForLambda()
3087 ? CheckFallThroughDiagnostics::MakeForCoroutine(D)
3088 : CheckFallThroughDiagnostics::MakeForFunction(S, D)));
3093 if (P.enableCheckUnreachable) {
3106 if (P.enableThreadSafetyAnalysis) {
3109 threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
3111 Reporter.setIssueBetaWarnings(
true);
3113 Reporter.setVerbose(
true);
3116 &S.ThreadSafetyDeclCache);
3117 Reporter.emitDiagnostics();
3121 if (P.enableConsumedAnalysis) {
3122 consumed::ConsumedWarningsHandler WarningHandler(S);
3133 UninitValsDiagReporter reporter(S);
3140 ++NumUninitAnalysisFunctions;
3143 MaxUninitAnalysisVariablesPerFunction =
3144 std::max(MaxUninitAnalysisVariablesPerFunction,
3146 MaxUninitAnalysisBlockVisitsPerFunction =
3147 std::max(MaxUninitAnalysisBlockVisitsPerFunction,
3155 if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {
3159 LSStats, S.CollectStats);
3163 if (S.getLangOpts().ObjC && !S.getLangOpts().CPlusPlus &&
3164 shouldAnalyzeCalledOnceParameters(Diags, D->
getBeginLoc())) {
3166 CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);
3169 shouldAnalyzeCalledOnceConventions(Diags, D->
getBeginLoc()));
3173 bool FallThroughDiagFull =
3175 bool FallThroughDiagPerFunction = !Diags.
isIgnored(
3176 diag::warn_unannotated_fallthrough_per_function, D->
getBeginLoc());
3177 if (FallThroughDiagFull || FallThroughDiagPerFunction ||
3182 if (S.getLangOpts().ObjCWeak &&
3188 if (!Diags.
isIgnored(diag::warn_infinite_recursive_function,
3190 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
3197 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
3203 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->
getBeginLoc())) {
3212 ++NumFunctionsAnalyzed;
3216 NumCFGBlocks += cfg->getNumBlockIDs();
3217 MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
3218 cfg->getNumBlockIDs());
3220 ++NumFunctionsWithBadCFGs;
3226 llvm::errs() <<
"\n*** Analysis Based Warnings Stats:\n";
3228 unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
3229 unsigned AvgCFGBlocksPerFunction =
3230 !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
3231 llvm::errs() << NumFunctionsAnalyzed <<
" functions analyzed ("
3232 << NumFunctionsWithBadCFGs <<
" w/o CFGs).\n"
3233 <<
" " << NumCFGBlocks <<
" CFG blocks built.\n"
3234 <<
" " << AvgCFGBlocksPerFunction
3235 <<
" average CFG blocks per function.\n"
3236 <<
" " << MaxCFGBlocksPerFunction
3237 <<
" max CFG blocks per function.\n";
3239 unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
3240 : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
3241 unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
3242 : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
3243 llvm::errs() << NumUninitAnalysisFunctions
3244 <<
" functions analyzed for uninitialiazed variables\n"
3245 <<
" " << NumUninitAnalysisVariables <<
" variables analyzed.\n"
3246 <<
" " << AvgUninitVariablesPerFunction
3247 <<
" average variables per function.\n"
3248 <<
" " << MaxUninitAnalysisVariablesPerFunction
3249 <<
" max variables per function.\n"
3250 <<
" " << NumUninitAnalysisBlockVisits <<
" block visits.\n"
3251 <<
" " << AvgUninitBlockVisitsPerFunction
3252 <<
" average block visits per function.\n"
3253 <<
" " << MaxUninitAnalysisBlockVisitsPerFunction
3254 <<
" 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 LifetimeSafetyTUAnalysis(Sema &S, TranslationUnitDecl *TU, clang::lifetimes::LifetimeSafetyStats &LSStats)
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
bool AddParameterLifetimes
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.
The AST-based call graph.
void addToCallGraph(Decl *D)
Populate the call graph with the functions in the given declaration.
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.
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.
FunctionDecl * getDefinition()
Get the definition for this declaration.
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
bool CollectStats
Flag indicating whether or not to collect detailed statistics.
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.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
@ Quoted
'#include ""' paths, added by 'gcc -iquote'.
bool LE(InterpState &S, CodePtr OpPC)
void printStats(const LifetimeSafetyStats &Stats)
Utility function to print missing origin stats.
bool IsLifetimeSafetyDiagnosticEnabled(Sema &S, const Decl *D)
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetySemaHelper *SemaHelper, LifetimeSafetyStats &Stats, bool CollectStats)
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
A structure to hold the statistics related to LifetimeAnalysis.