48#include "llvm/ADT/ArrayRef.h"
49#include "llvm/ADT/BitVector.h"
50#include "llvm/ADT/DenseMap.h"
51#include "llvm/ADT/MapVector.h"
52#include "llvm/ADT/STLFunctionalExtras.h"
53#include "llvm/ADT/SmallVector.h"
54#include "llvm/ADT/StringRef.h"
55#include "llvm/Support/Debug.h"
70 SourceRange PreviousSilenceableCondVal;
73 UnreachableCodeHandler(Sema &
s) : S(
s) {}
76 SourceRange SilenceableCondVal, SourceRange R1,
77 SourceRange R2,
bool HasFallThroughAttr)
override {
81 if (HasFallThroughAttr &&
82 !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr,
88 if (PreviousSilenceableCondVal.isValid() &&
90 PreviousSilenceableCondVal == SilenceableCondVal)
92 PreviousSilenceableCondVal = SilenceableCondVal;
94 unsigned diag = diag::warn_unreachable;
97 diag = diag::warn_unreachable_break;
100 diag = diag::warn_unreachable_return;
103 diag = diag::warn_unreachable_loop_increment;
109 S.Diag(L, diag) << R1 << R2;
112 if (
Open.isValid()) {
113 SourceLocation Close = SilenceableCondVal.
getEnd();
114 Close = S.getLocForEndOfToken(Close);
116 S.Diag(
Open, diag::note_unreachable_silence)
137 UnreachableCodeHandler UC(S);
147 LogicalErrorHandler(Sema &S) : S(S) {}
149 static bool HasMacroID(
const Expr *E) {
154 for (
const Stmt *SubStmt : E->
children())
155 if (
const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt))
156 if (HasMacroID(SubExpr))
162 void logicAlwaysTrue(
const BinaryOperator *B,
bool isAlwaysTrue)
override {
166 unsigned DiagID = isAlwaysTrue
167 ? diag::warn_tautological_negation_or_compare
168 : diag::warn_tautological_negation_and_compare;
173 void compareAlwaysTrue(
const BinaryOperator *B,
174 bool isAlwaysTrueOrFalse)
override {
179 S.Diag(B->
getExprLoc(), diag::warn_tautological_overlap_comparison)
180 << DiagRange << isAlwaysTrueOrFalse;
183 void compareBitwiseEquality(
const BinaryOperator *B,
184 bool isAlwaysTrue)
override {
189 S.Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_always)
190 << DiagRange << isAlwaysTrue;
193 void compareBitwiseOr(
const BinaryOperator *B)
override {
198 S.Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;
201 static bool hasActiveDiagnostics(DiagnosticsEngine &Diags,
202 SourceLocation Loc) {
203 return !Diags.
isIgnored(diag::warn_tautological_overlap_comparison, Loc) ||
204 !Diags.
isIgnored(diag::warn_comparison_bitwise_or, Loc) ||
205 !Diags.
isIgnored(diag::warn_tautological_negation_and_compare, Loc);
219 for (
const auto &B :
Block) {
233 if (isa_and_nonnull<TemplateSpecializationType>(NNS.getAsType()))
249 bool foundRecursion =
false;
254 WorkList.push_back(&cfg->
getEntry());
256 while (!WorkList.empty()) {
259 for (
auto I =
Block->succ_begin(), E =
Block->succ_end(); I != E; ++I) {
261 if (!Visited.insert(SuccBlock).second)
265 if (ExitID == SuccBlock->getBlockID())
270 foundRecursion =
true;
274 WorkList.push_back(SuccBlock);
278 return foundRecursion;
314 Stack.push_back(&ThrowBlock);
317 while (!Stack.empty()) {
318 CFGBlock &UnwindBlock = *Stack.pop_back_val();
320 for (
auto &Succ : UnwindBlock.
succs()) {
321 if (!Succ.isReachable() || Queued[Succ->getBlockID()])
328 dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
329 QualType Caught = Catch->getCaughtType();
336 Stack.push_back(Succ);
337 Queued[Succ->getBlockID()] =
true;
351 if (!Reachable[B->getBlockID()])
354 std::optional<CFGStmt> S = E.getAs<
CFGStmt>();
357 if (
auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))
367 S.
Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
373 getAs<FunctionProtoType>())
398 if (FPT->isNothrow() || FD->
hasAttr<NoThrowAttr>())
407 if (
auto *FD = dyn_cast<FunctionDecl>(DRef->getDecl()))
408 return FD->isNoReturn();
427struct TransferFunctions :
public StmtVisitor<TransferFunctions> {
429 std::optional<bool> AllValuesAreNoReturn;
431 TransferFunctions(
const VarDecl *VD) : Var(VD) {}
433 void reset() { AllValuesAreNoReturn = std::nullopt; }
435 void VisitDeclStmt(DeclStmt *DS) {
436 for (
auto *DI : DS->
decls())
437 if (
auto *VD = dyn_cast<VarDecl>(DI))
438 if (VarDecl *Def = VD->getDefinition())
443 void VisitUnaryOperator(UnaryOperator *UO) {
447 if (DRef->getDecl() == Var)
448 AllValuesAreNoReturn =
false;
452 void VisitBinaryOperator(BinaryOperator *BO) {
455 if (DRef->getDecl() == Var)
459 void VisitCallExpr(CallExpr *CE) {
462 const Expr *Arg = *I;
465 if (
auto VD = dyn_cast<VarDecl>(DRef->getDecl()))
466 if (VD->getDefinition() == Var)
467 AllValuesAreNoReturn =
false;
493 using MapTy = llvm::DenseMap<const CFGBlock *, std::optional<bool>>;
494 using ValueTy = MapTy::value_type;
496 BlocksToCheck[&VarBlk] = std::nullopt;
497 const auto BlockSatisfiesCondition = [](ValueTy Item) {
498 return Item.getSecond().value_or(
false);
501 TransferFunctions TF(VD);
503 llvm::DenseSet<const CFGBlock *> Visited;
506 if (Visited.contains(B))
512 if (std::optional<CFGStmt> cs = ri->getAs<
CFGStmt>()) {
513 const Stmt *S = cs->getStmt();
515 TF.Visit(
const_cast<Stmt *
>(S));
516 if (TF.AllValuesAreNoReturn) {
517 if (!TF.AllValuesAreNoReturn.value())
519 BlocksToCheck[B] =
true;
526 if (llvm::all_of(BlocksToCheck, BlockSatisfiesCondition))
531 if (!BlocksToCheck[B]) {
533 BlocksToCheck.erase(B);
534 for (
const auto &PredBlk : B->preds())
535 if (!BlocksToCheck.contains(PredBlk))
536 BlocksToCheck[PredBlk] = std::nullopt;
579 for (
const auto *B : *cfg) {
580 if (!live[B->getBlockID()]) {
581 if (B->preds().empty()) {
582 const Stmt *Term = B->getTerminatorStmt();
583 if (isa_and_nonnull<CXXTryStmt>(Term))
595 bool HasLiveReturn =
false;
596 bool HasFakeEdge =
false;
597 bool HasPlainEdge =
false;
598 bool HasAbnormalEdge =
false;
616 HasAbnormalEdge =
true;
625 for ( ; ri != re ; ++ri)
633 HasAbnormalEdge =
true;
644 HasLiveReturn =
true;
658 HasLiveReturn =
true;
662 HasAbnormalEdge =
true;
666 HasAbnormalEdge =
true;
669 if (
auto *
Call = dyn_cast<CallExpr>(S)) {
670 const Expr *Callee =
Call->getCallee();
671 if (Callee->getType()->isPointerType())
673 dyn_cast<DeclRefExpr>(Callee->IgnoreParenImpCasts()))
674 if (
auto *VD = dyn_cast<VarDecl>(DeclRef->getDecl()))
676 HasAbnormalEdge =
true;
688 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
698struct CheckFallThroughDiagnostics {
699 unsigned diag_FallThrough_HasNoReturn = 0;
700 unsigned diag_FallThrough_ReturnsNonVoid = 0;
701 unsigned diag_NeverFallThroughOrReturn = 0;
703 SourceLocation FuncLoc;
705 static CheckFallThroughDiagnostics MakeForFunction(Sema &S,
707 CheckFallThroughDiagnostics D;
708 D.FuncLoc =
Func->getLocation();
709 D.diag_FallThrough_HasNoReturn = diag::warn_noreturn_has_return_expr;
710 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
714 bool isVirtualMethod =
false;
715 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(
Func))
716 isVirtualMethod =
Method->isVirtual();
720 if (
const FunctionDecl *
Function = dyn_cast<FunctionDecl>(
Func)) {
724 D.diag_FallThrough_ReturnsNonVoid = diag::ext_main_no_return;
729 D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function;
731 D.FunKind = diag::FalloffFunctionKind::Function;
735 static CheckFallThroughDiagnostics MakeForCoroutine(
const Decl *
Func) {
736 CheckFallThroughDiagnostics D;
737 D.FuncLoc =
Func->getLocation();
738 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
739 D.FunKind = diag::FalloffFunctionKind::Coroutine;
743 static CheckFallThroughDiagnostics MakeForBlock() {
744 CheckFallThroughDiagnostics D;
745 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;
746 D.diag_FallThrough_ReturnsNonVoid = diag::err_falloff_nonvoid;
747 D.FunKind = diag::FalloffFunctionKind::Block;
751 static CheckFallThroughDiagnostics MakeForLambda() {
752 CheckFallThroughDiagnostics D;
753 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;
754 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
755 D.FunKind = diag::FalloffFunctionKind::Lambda;
759 bool checkDiagnostics(DiagnosticsEngine &D,
bool ReturnsVoid,
760 bool HasNoReturn)
const {
761 if (FunKind == diag::FalloffFunctionKind::Function) {
762 return (ReturnsVoid ||
763 D.
isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&
765 D.
isIgnored(diag::warn_noreturn_has_return_expr, FuncLoc)) &&
767 D.
isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));
769 if (FunKind == diag::FalloffFunctionKind::Coroutine) {
770 return (ReturnsVoid ||
771 D.
isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&
775 return ReturnsVoid && !HasNoReturn;
787 const CheckFallThroughDiagnostics &CD,
790 bool ReturnsVoid =
false;
791 bool HasNoReturn =
false;
793 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
794 if (
const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
795 ReturnsVoid = CBody->getFallthroughHandler() !=
nullptr;
797 ReturnsVoid = FD->getReturnType()->isVoidType();
798 HasNoReturn = FD->isNoReturn() || FD->hasAttr<InferredNoReturnAttr>();
800 else if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
801 ReturnsVoid = MD->getReturnType()->isVoidType();
802 HasNoReturn = MD->hasAttr<NoReturnAttr>();
807 if (FT->getReturnType()->isVoidType())
809 if (FT->getNoReturnAttr())
817 if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
833 if (CD.diag_FallThrough_HasNoReturn)
834 S.
Diag(RBrace, CD.diag_FallThrough_HasNoReturn) << CD.FunKind;
835 }
else if (!ReturnsVoid && CD.diag_FallThrough_ReturnsNonVoid) {
839 if (
const auto *CS = dyn_cast<CompoundStmt>(Body);
840 CS && !CS->body_empty()) {
841 const Stmt *LastStmt = CS->body_back();
843 if (
const auto *EWC = dyn_cast<ExprWithCleanups>(LastStmt)) {
844 LastStmt = EWC->getSubExpr();
846 if (
const auto *CE = dyn_cast<CallExpr>(LastStmt)) {
848 Callee && Callee->hasAttr<InferredNoReturnAttr>()) {
859 S.
Diag(RBrace, CD.diag_FallThrough_ReturnsNonVoid)
860 << CD.FunKind << NotInAllControlPaths;
864 if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
865 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
866 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
867 }
else if (
const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
868 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
870 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
889 const DeclRefExpr *Needle;
892 typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited;
894 ContainsReference(ASTContext &Context,
const DeclRefExpr *Needle)
895 : Inherited(Context), FoundReference(
false), Needle(Needle) {}
897 void VisitExpr(
const Expr *E) {
902 Inherited::VisitExpr(E);
905 void VisitDeclRefExpr(
const DeclRefExpr *E) {
907 FoundReference =
true;
912 bool doesContainReference()
const {
return FoundReference; }
920 S.
Diag(VD->
getLocation(), diag::note_block_var_fixit_add_initialization)
941 S.
Diag(Loc, diag::note_var_fixit_add_initialization) << VD->
getDeclName()
949 const Stmt *Else,
bool CondVal,
973 bool IsCapturedByBlock) {
974 bool Diagnosed =
false;
1007 const Stmt *Term = I->Terminator;
1017 int RemoveDiagKind = -1;
1018 const char *FixitStr =
1019 S.
getLangOpts().CPlusPlus ? (I->Output ?
"true" :
"false")
1020 : (I->Output ?
"1" :
"0");
1023 switch (Term ? Term->
getStmtClass() : Stmt::DeclStmtClass) {
1030 case Stmt::IfStmtClass: {
1037 I->Output, Fixit1, Fixit2);
1040 case Stmt::ConditionalOperatorClass: {
1047 I->Output, Fixit1, Fixit2);
1050 case Stmt::BinaryOperatorClass: {
1058 if ((BO->
getOpcode() == BO_LAnd && I->Output) ||
1059 (BO->
getOpcode() == BO_LOr && !I->Output))
1070 case Stmt::WhileStmtClass:
1077 case Stmt::ForStmtClass:
1087 case Stmt::CXXForRangeStmtClass:
1088 if (I->Output == 1) {
1100 case Stmt::DoStmtClass:
1103 Range =
cast<DoStmt>(Term)->getCond()->getSourceRange();
1109 case Stmt::CaseStmtClass:
1114 case Stmt::DefaultStmtClass:
1121 S.
Diag(Range.getBegin(), diag::warn_sometimes_uninit_var)
1122 << VD->
getDeclName() << IsCapturedByBlock << DiagKind
1123 << Str << I->Output << Range;
1126 if (RemoveDiagKind != -1)
1128 << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
1162 bool alwaysReportSelfInit =
false) {
1176 if (!alwaysReportSelfInit && DRE ==
Initializer->IgnoreParenImpCasts())
1179 ContainsReference CR(S.
Context, DRE);
1181 if (CR.doesContainReference()) {
1182 S.
Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
1193 diag::warn_uninit_byref_blockvar_captured_by_block)
1213 FallthroughMapper(Sema &S) : FoundSwitchStatements(
false), S(S) {
1214 ShouldWalkTypesOfTypeLocs =
false;
1217 bool foundSwitchStatements()
const {
return FoundSwitchStatements; }
1219 void markFallthroughVisited(
const AttributedStmt *Stmt) {
1220 bool Found = FallthroughStmts.erase(Stmt);
1225 typedef llvm::SmallPtrSet<const AttributedStmt *, 8> AttrStmts;
1227 const AttrStmts &getFallthroughStmts()
const {
return FallthroughStmts; }
1229 void fillReachableBlocks(CFG *Cfg) {
1230 assert(ReachableBlocks.empty() &&
"ReachableBlocks already filled");
1231 std::deque<const CFGBlock *> BlockQueue;
1233 ReachableBlocks.insert(&Cfg->
getEntry());
1234 BlockQueue.push_back(&Cfg->
getEntry());
1239 for (
const auto *B : *Cfg) {
1240 const Stmt *L = B->getLabel();
1241 if (isa_and_nonnull<SwitchCase>(L) && ReachableBlocks.insert(B).second)
1242 BlockQueue.push_back(B);
1245 while (!BlockQueue.empty()) {
1246 const CFGBlock *P = BlockQueue.front();
1247 BlockQueue.pop_front();
1248 for (
const CFGBlock *B : P->
succs()) {
1249 if (B && ReachableBlocks.insert(B).second)
1250 BlockQueue.push_back(B);
1255 bool checkFallThroughIntoBlock(
const CFGBlock &B,
int &AnnotatedCnt,
1256 bool IsTemplateInstantiation) {
1257 assert(!ReachableBlocks.empty() &&
"ReachableBlocks empty");
1259 int UnannotatedCnt = 0;
1263 while (!BlockQueue.empty()) {
1264 const CFGBlock *P = BlockQueue.
front();
1265 BlockQueue.pop_front();
1270 if (isa_and_nonnull<SwitchStmt>(Term))
1273 const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->
getLabel());
1277 const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->
getLabel());
1281 if (!ReachableBlocks.count(P)) {
1282 for (
const CFGElement &Elem : llvm::reverse(*P)) {
1283 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) {
1284 if (
const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
1288 if (!IsTemplateInstantiation)
1289 S.Diag(AS->getBeginLoc(),
1290 diag::warn_unreachable_fallthrough_attr);
1291 markFallthroughVisited(AS);
1310 if (
const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {
1311 markFallthroughVisited(AS);
1319 std::back_inserter(BlockQueue));
1325 return !!UnannotatedCnt;
1328 bool VisitAttributedStmt(AttributedStmt *S)
override {
1329 if (asFallThroughAttr(S))
1330 FallthroughStmts.insert(S);
1334 bool VisitSwitchStmt(SwitchStmt *S)
override {
1335 FoundSwitchStatements =
true;
1341 bool TraverseDecl(Decl *D)
override {
return true; }
1344 bool TraverseLambdaExpr(
LambdaExpr *LE)
override {
1346 for (
const auto C : zip(
LE->captures(),
LE->capture_inits()))
1347 TraverseLambdaCapture(LE, &std::get<0>(
C), std::get<1>(
C));
1353 static const AttributedStmt *asFallThroughAttr(
const Stmt *S) {
1354 if (
const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
1361 static const Stmt *
getLastStmt(
const CFGBlock &B) {
1364 for (
const CFGElement &Elem : llvm::reverse(B))
1365 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
1366 return CS->getStmt();
1370 if (
const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.
getLabel()))
1377 bool FoundSwitchStatements;
1378 AttrStmts FallthroughStmts;
1380 llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
1387 tok::l_square, tok::l_square,
1389 tok::r_square, tok::r_square
1395 tok::r_square, tok::r_square
1400 StringRef MacroName;
1401 if (PreferClangAttr)
1403 if (MacroName.empty())
1405 if (MacroName.empty() && !PreferClangAttr)
1407 if (MacroName.empty()) {
1408 if (!PreferClangAttr)
1409 MacroName =
"[[fallthrough]]";
1411 MacroName =
"[[clang::fallthrough]]";
1413 MacroName =
"__attribute__((fallthrough))";
1420 FallthroughMapper FM(S);
1421 FM.TraverseStmt(AC.
getBody());
1423 if (!FM.foundSwitchStatements())
1426 if (PerFunction && FM.getFallthroughStmts().empty())
1434 FM.fillReachableBlocks(Cfg);
1436 for (
const CFGBlock *B : llvm::reverse(*Cfg)) {
1439 if (!isa_and_nonnull<SwitchCase>(Label))
1444 bool IsTemplateInstantiation =
false;
1446 IsTemplateInstantiation = Function->isTemplateInstantiation();
1447 if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,
1448 IsTemplateInstantiation))
1452 PerFunction ? diag::warn_unannotated_fallthrough_per_function
1453 : diag::warn_unannotated_fallthrough);
1455 if (!AnnotatedCnt) {
1466 if (!(B->
empty() && isa_and_nonnull<BreakStmt>(Term))) {
1470 TextToInsert +=
"; ";
1471 S.
Diag(L, diag::note_insert_fallthrough_fixit)
1472 << AnnotationSpelling
1475 S.
Diag(L, diag::note_insert_break_fixit)
1480 for (
const auto *F : FM.getFallthroughStmts())
1481 S.
Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement);
1490 case Stmt::ForStmtClass:
1491 case Stmt::WhileStmtClass:
1492 case Stmt::CXXForRangeStmtClass:
1493 case Stmt::ObjCForCollectionStmtClass:
1495 case Stmt::DoStmtClass: {
1499 return Result.
Val.
getInt().getBoolValue();
1516 typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
1525 for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end();
1527 const WeakUseVector &Uses = I->second;
1530 WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
1531 for ( ; UI != UE; ++UI) {
1544 if (UI == Uses.begin()) {
1545 WeakUseVector::const_iterator UI2 = UI;
1546 for (++UI2; UI2 != UE; ++UI2)
1547 if (UI2->isUnsafe())
1551 if (!
isInLoop(Ctx, PM, UI->getUseExpr()))
1554 const WeakObjectProfileTy &Profile = I->first;
1555 if (!Profile.isExactProfile())
1560 Base = Profile.getProperty();
1561 assert(
Base &&
"A profile always has a base or property.");
1563 if (
const VarDecl *BaseVar = dyn_cast<VarDecl>(
Base))
1569 UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
1572 if (UsesByStmt.empty())
1577 llvm::sort(UsesByStmt,
1578 [&
SM](
const StmtUsesPair &LHS,
const StmtUsesPair &RHS) {
1579 return SM.isBeforeInTranslationUnit(LHS.first->getBeginLoc(),
1580 RHS.first->getBeginLoc());
1596 FunctionKind =
Block;
1598 FunctionKind = Lambda;
1600 FunctionKind = Method;
1602 FunctionKind = Function;
1605 for (
const auto &P : UsesByStmt) {
1606 const Stmt *FirstRead = P.first;
1607 const WeakObjectProfileTy &Key = P.second->first;
1608 const WeakUseVector &Uses = P.second->second;
1616 if (Key.isExactProfile())
1617 DiagKind = diag::warn_arc_repeated_use_of_weak;
1619 DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
1631 const NamedDecl *KeyProp = Key.getProperty();
1633 ObjectKind = Variable;
1635 ObjectKind = Property;
1637 ObjectKind = ImplicitProperty;
1641 llvm_unreachable(
"Unexpected weak object kind!");
1646 if (Prop->hasAttr<IBOutletAttr>())
1651 <<
int(ObjectKind) << KeyProp <<
int(FunctionKind)
1655 for (
const auto &Use : Uses) {
1656 if (Use.getUseExpr() == FirstRead)
1658 S.
Diag(Use.getUseExpr()->getBeginLoc(),
1659 diag::note_arc_weak_also_accessed_here)
1660 << Use.getUseExpr()->getSourceRange();
1668typedef std::pair<PartialDiagnosticAt, OptionalNotes>
DelayedDiag;
1669typedef std::list<DelayedDiag>
DiagList;
1671struct SortDiagBySourceLocation {
1673 SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {}
1675 bool operator()(
const DelayedDiag &left,
const DelayedDiag &right) {
1678 return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
1687 typedef SmallVector<UninitUse, 2> UsesVec;
1688 typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
1692 typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
1696 UninitValsDiagReporter(Sema &S) : S(S) {}
1699 MappedType &getUses(
const VarDecl *vd) {
1700 MappedType &
V = uses[vd];
1701 if (!
V.getPointer())
1702 V.setPointer(
new UsesVec());
1706 void handleUseOfUninitVariable(
const VarDecl *vd,
1707 const UninitUse &use)
override {
1708 getUses(vd).getPointer()->push_back(use);
1711 void handleSelfInit(
const VarDecl *vd)
override { getUses(vd).setInt(
true); }
1714 for (
const auto &P : uses) {
1715 const VarDecl *vd = P.first;
1716 const MappedType &
V = P.second;
1718 UsesVec *vec =
V.getPointer();
1719 bool hasSelfInit =
V.getInt();
1721 diagnoseUnitializedVar(vd, hasSelfInit, vec);
1731 static bool hasAlwaysUninitializedUse(
const UsesVec* vec) {
1732 return llvm::any_of(*vec, [](
const UninitUse &U) {
1742 void diagnoseUnitializedVar(
const VarDecl *vd,
bool hasSelfInit,
1747 if (hasSelfInit && hasAlwaysUninitializedUse(vec)) {
1758 llvm::sort(*vec, [](
const UninitUse &a,
const UninitUse &
b) {
1762 return b.isConstRefOrPtrUse();
1769 for (
const auto &U : *vec) {
1778 UninitUse Use = hasSelfInit ? UninitUse(U.
getUser(),
false) : U;
1787class CalledOnceInterProceduralData {
1790 void addDelayedWarning(
const BlockDecl *
Block,
1792 DelayedBlockWarnings[
Block].emplace_back(std::move(
Warning));
1795 void flushWarnings(
const BlockDecl *
Block, Sema &S) {
1797 S.
Diag(Delayed.first, Delayed.second);
1799 discardWarnings(
Block);
1802 void discardWarnings(
const BlockDecl *
Block) {
1803 DelayedBlockWarnings.erase(
Block);
1807 using DelayedDiagnostics = SmallVector<PartialDiagnosticAt, 2>;
1808 llvm::DenseMap<const BlockDecl *, DelayedDiagnostics> DelayedBlockWarnings;
1813 CalledOnceCheckReporter(Sema &S, CalledOnceInterProceduralData &Data)
1814 : S(S), Data(Data) {}
1815 void handleDoubleCall(
const ParmVarDecl *
Parameter,
const Expr *
Call,
1816 const Expr *PrevCall,
bool IsCompletionHandler,
1817 bool Poised)
override {
1818 auto DiagToReport = IsCompletionHandler
1819 ? diag::warn_completion_handler_called_twice
1820 : diag::warn_called_once_gets_called_twice;
1822 S.Diag(PrevCall->
getBeginLoc(), diag::note_called_once_gets_called_twice)
1826 void handleNeverCalled(
const ParmVarDecl *
Parameter,
1827 bool IsCompletionHandler)
override {
1828 auto DiagToReport = IsCompletionHandler
1829 ? diag::warn_completion_handler_never_called
1830 : diag::warn_called_once_never_called;
1831 S.Diag(
Parameter->getBeginLoc(), DiagToReport)
1837 bool IsCalledDirectly,
1838 bool IsCompletionHandler)
override {
1839 auto DiagToReport = IsCompletionHandler
1840 ? diag::warn_completion_handler_never_called_when
1841 : diag::warn_called_once_never_called_when;
1845 << (
unsigned)Reason);
1855 void handleCapturedNeverCalled(
const ParmVarDecl *
Parameter,
1857 bool IsCompletionHandler)
override {
1858 auto DiagToReport = IsCompletionHandler
1859 ? diag::warn_completion_handler_never_called
1860 : diag::warn_called_once_never_called;
1866 handleBlockThatIsGuaranteedToBeCalledOnce(
const BlockDecl *
Block)
override {
1867 Data.flushWarnings(
Block, S);
1870 void handleBlockWithNoGuarantees(
const BlockDecl *
Block)
override {
1871 Data.discardWarnings(
Block);
1876 CalledOnceInterProceduralData &Data;
1879constexpr unsigned CalledOnceWarnings[] = {
1880 diag::warn_called_once_never_called,
1881 diag::warn_called_once_never_called_when,
1882 diag::warn_called_once_gets_called_twice};
1884constexpr unsigned CompletionHandlerWarnings[]{
1885 diag::warn_completion_handler_never_called,
1886 diag::warn_completion_handler_never_called_when,
1887 diag::warn_completion_handler_called_twice};
1892 return llvm::any_of(DiagIDs, [&Diags, At](
unsigned DiagID) {
1899 return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);
1904 return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||
1905 shouldAnalyzeCalledOnceConventions(Diags, At);
1915class ThreadSafetyReporter :
public clang::threadSafety::ThreadSafetyHandler {
1918 SourceLocation FunLocation, FunEndLocation;
1920 const FunctionDecl *CurrentFunction;
1924 if (Verbose && CurrentFunction) {
1926 S.PDiag(diag::note_thread_warning_in_fun)
1927 << CurrentFunction);
1935 if (Verbose && CurrentFunction) {
1937 S.PDiag(diag::note_thread_warning_in_fun)
1938 << CurrentFunction);
1939 ONS.push_back(std::move(FNote));
1947 ONS.push_back(Note1);
1948 ONS.push_back(Note2);
1949 if (Verbose && CurrentFunction) {
1951 S.PDiag(diag::note_thread_warning_in_fun)
1952 << CurrentFunction);
1953 ONS.push_back(std::move(FNote));
1958 OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) {
1961 LocLocked, S.PDiag(diag::note_locked_here) << Kind))
1965 OptionalNotes makeUnlockedHereNote(SourceLocation LocUnlocked,
1969 LocUnlocked, S.PDiag(diag::note_unlocked_here) << Kind))
1973 OptionalNotes makeManagedMismatchNoteForParam(SourceLocation DeclLoc) {
1977 S.PDiag(diag::note_managed_mismatch_here_for_param)))
1982 ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
1983 : S(S), FunLocation(FL), FunEndLocation(FEL),
1986 void setVerbose(
bool b) { Verbose =
b; }
1993 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
1994 for (
const auto &
Diag : Warnings) {
1995 S.Diag(
Diag.first.first,
Diag.first.second);
1996 for (
const auto &
Note :
Diag.second)
2001 void handleUnmatchedUnderlyingMutexes(SourceLocation Loc, SourceLocation DLoc,
2002 Name scopeName, StringRef Kind,
2003 Name expected, Name actual)
override {
2005 S.PDiag(diag::warn_unmatched_underlying_mutexes)
2006 << Kind << scopeName << expected << actual);
2007 Warnings.emplace_back(std::move(
Warning),
2008 makeManagedMismatchNoteForParam(DLoc));
2011 void handleExpectMoreUnderlyingMutexes(SourceLocation Loc,
2012 SourceLocation DLoc, Name scopeName,
2014 Name expected)
override {
2016 Loc, S.PDiag(diag::warn_expect_more_underlying_mutexes)
2017 << Kind << scopeName << expected);
2018 Warnings.emplace_back(std::move(
Warning),
2019 makeManagedMismatchNoteForParam(DLoc));
2022 void handleExpectFewerUnderlyingMutexes(SourceLocation Loc,
2023 SourceLocation DLoc, Name scopeName,
2025 Name actual)
override {
2027 Loc, S.PDiag(diag::warn_expect_fewer_underlying_mutexes)
2028 << Kind << scopeName << actual);
2029 Warnings.emplace_back(std::move(
Warning),
2030 makeManagedMismatchNoteForParam(DLoc));
2033 void handleInvalidLockExp(SourceLocation Loc)
override {
2036 Warnings.emplace_back(std::move(
Warning), getNotes());
2039 void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc,
2040 SourceLocation LocPreviousUnlock)
override {
2044 << Kind << LockName);
2045 Warnings.emplace_back(std::move(
Warning),
2046 makeUnlockedHereNote(LocPreviousUnlock, Kind));
2049 void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
2051 SourceLocation LocLocked,
2052 SourceLocation LocUnlock)
override {
2054 LocUnlock = FunLocation;
2056 LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch)
2057 << Kind << LockName << Received << Expected);
2058 Warnings.emplace_back(std::move(
Warning),
2059 makeLockedHereNote(LocLocked, Kind));
2062 void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked,
2063 SourceLocation LocDoubleLock)
override {
2065 LocDoubleLock = FunLocation;
2067 << Kind << LockName);
2068 Warnings.emplace_back(std::move(
Warning),
2069 makeLockedHereNote(LocLocked, Kind));
2072 void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
2073 SourceLocation LocLocked,
2074 SourceLocation LocEndOfScope,
2076 bool ReentrancyMismatch)
override {
2077 unsigned DiagID = 0;
2080 DiagID = diag::warn_lock_some_predecessors;
2083 DiagID = diag::warn_expecting_lock_held_on_loop;
2086 DiagID = diag::warn_no_unlock;
2089 DiagID = diag::warn_expecting_locked;
2093 LocEndOfScope = FunEndLocation;
2097 << ReentrancyMismatch);
2098 Warnings.emplace_back(std::move(
Warning),
2099 makeLockedHereNote(LocLocked, Kind));
2102 void handleExclusiveAndShared(StringRef Kind, Name LockName,
2103 SourceLocation Loc1,
2104 SourceLocation Loc2)
override {
2106 S.PDiag(diag::warn_lock_exclusive_and_shared)
2107 << Kind << LockName);
2109 << Kind << LockName);
2110 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2114 AccessKind AK, SourceLocation Loc)
override {
2115 unsigned DiagID = 0;
2122 DiagID = diag::warn_variable_requires_any_lock;
2129 DiagID = diag::warn_var_deref_requires_any_lock;
2132 llvm_unreachable(
"Only works for variables");
2137 Warnings.emplace_back(std::move(
Warning), getNotes());
2140 void handleMutexNotHeld(StringRef Kind,
const NamedDecl *D,
2143 Name *PossibleMatch)
override {
2144 unsigned DiagID = 0;
2145 if (PossibleMatch) {
2148 DiagID = diag::warn_variable_requires_lock_precise;
2151 DiagID = diag::warn_var_deref_requires_lock_precise;
2154 DiagID = diag::warn_fun_requires_lock_precise;
2157 DiagID = diag::warn_guarded_pass_by_reference;
2160 DiagID = diag::warn_pt_guarded_pass_by_reference;
2163 DiagID = diag::warn_guarded_return_by_reference;
2166 DiagID = diag::warn_pt_guarded_return_by_reference;
2169 DiagID = diag::warn_guarded_pass_pointer;
2172 DiagID = diag::warn_pt_guarded_pass_pointer;
2175 DiagID = diag::warn_guarded_return_pointer;
2178 DiagID = diag::warn_pt_guarded_return_pointer;
2188 S.PDiag(diag::note_guarded_by_declared_here)
2190 Warnings.emplace_back(std::move(
Warning), getNotes(
Note, VNote));
2192 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2196 DiagID = diag::warn_variable_requires_lock;
2199 DiagID = diag::warn_var_deref_requires_lock;
2202 DiagID = diag::warn_fun_requires_lock;
2205 DiagID = diag::warn_guarded_pass_by_reference;
2208 DiagID = diag::warn_pt_guarded_pass_by_reference;
2211 DiagID = diag::warn_guarded_return_by_reference;
2214 DiagID = diag::warn_pt_guarded_return_by_reference;
2217 DiagID = diag::warn_guarded_pass_pointer;
2220 DiagID = diag::warn_pt_guarded_pass_pointer;
2223 DiagID = diag::warn_guarded_return_pointer;
2226 DiagID = diag::warn_pt_guarded_return_pointer;
2234 S.PDiag(diag::note_guarded_by_declared_here));
2235 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2237 Warnings.emplace_back(std::move(
Warning), getNotes());
2241 void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
2242 SourceLocation Loc)
override {
2244 S.PDiag(diag::warn_acquire_requires_negative_cap)
2245 << Kind << LockName << Neg);
2246 Warnings.emplace_back(std::move(
Warning), getNotes());
2249 void handleNegativeNotHeld(
const NamedDecl *D, Name LockName,
2250 SourceLocation Loc)
override {
2252 Loc, S.PDiag(diag::warn_fun_requires_negative_cap) << D << LockName);
2253 Warnings.emplace_back(std::move(
Warning), getNotes());
2256 void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
2257 SourceLocation Loc)
override {
2259 << Kind << FunName << LockName);
2260 Warnings.emplace_back(std::move(
Warning), getNotes());
2263 void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
2264 SourceLocation Loc)
override {
2266 S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
2267 Warnings.emplace_back(std::move(
Warning), getNotes());
2270 void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc)
override {
2272 S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
2273 Warnings.emplace_back(std::move(
Warning), getNotes());
2276 void enterFunction(
const FunctionDecl* FD)
override {
2277 CurrentFunction = FD;
2280 void leaveFunction(
const FunctionDecl* FD)
override {
2281 CurrentFunction =
nullptr;
2302 ConsumedWarningsHandler(Sema &S) : S(S) {}
2305 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
2306 for (
const auto &
Diag : Warnings) {
2307 S.Diag(
Diag.first.first,
Diag.first.second);
2308 for (
const auto &
Note :
Diag.second)
2313 void warnLoopStateMismatch(SourceLocation Loc,
2314 StringRef VariableName)
override {
2321 void warnParamReturnTypestateMismatch(SourceLocation Loc,
2322 StringRef VariableName,
2323 StringRef ExpectedState,
2324 StringRef ObservedState)
override {
2327 diag::warn_param_return_typestate_mismatch) << VariableName <<
2328 ExpectedState << ObservedState);
2333 void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
2334 StringRef ObservedState)
override {
2337 diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
2342 void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
2343 StringRef TypeName)
override {
2345 diag::warn_return_typestate_for_unconsumable_type) << TypeName);
2350 void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
2351 StringRef ObservedState)
override {
2354 diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
2359 void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
2360 SourceLocation Loc)
override {
2363 diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
2368 void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
2369 StringRef State, SourceLocation Loc)
override {
2372 MethodName << VariableName << State);
2388 bool SuggestSuggestions;
2392 std::string listVariableGroupAsString(
2393 const VarDecl *VD,
const ArrayRef<const VarDecl *> &VarGroupForVD)
const {
2394 if (VarGroupForVD.size() <= 1)
2397 std::vector<StringRef> VarNames;
2398 auto PutInQuotes = [](StringRef S) -> std::string {
2399 return "'" + S.str() +
"'";
2402 for (
auto *
V : VarGroupForVD) {
2405 VarNames.push_back(
V->getName());
2407 if (VarNames.size() == 1) {
2408 return PutInQuotes(VarNames[0]);
2410 if (VarNames.size() == 2) {
2411 return PutInQuotes(VarNames[0]) +
" and " + PutInQuotes(VarNames[1]);
2413 assert(VarGroupForVD.size() > 3);
2414 const unsigned N = VarNames.size() -
2416 std::string AllVars =
"";
2418 for (
unsigned I = 0; I < N; ++I)
2419 AllVars.append(PutInQuotes(VarNames[I]) +
", ");
2420 AllVars.append(PutInQuotes(VarNames[N]) +
", and " +
2421 PutInQuotes(VarNames[N + 1]));
2426 UnsafeBufferUsageReporter(Sema &S,
bool SuggestSuggestions)
2427 : S(S), SuggestSuggestions(SuggestSuggestions) {}
2429 void handleUnsafeOperation(
const Stmt *Operation,
bool IsRelatedToDecl,
2430 ASTContext &Ctx)
override {
2433 unsigned MsgParam = 0;
2434 NamedDecl *D =
nullptr;
2435 if (
const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
2436 Loc = ASE->getBase()->getExprLoc();
2437 Range = ASE->getBase()->getSourceRange();
2439 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
2441 if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
2442 Op == BO_SubAssign) {
2452 }
else if (
const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
2454 if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
2463 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2467 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2469 D = ME->getMemberDecl();
2471 }
else if (
const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) {
2472 QualType destType = ECE->getType();
2473 bool destTypeComplete =
true;
2479 destTypeComplete = D->isCompleteDefinition();
2483 if (destTypeComplete) {
2485 QualType srcType = ECE->getSubExpr()->getType();
2495 if (
const auto *CE = dyn_cast<CXXMemberCallExpr>(
2496 ECE->getSubExpr()->IgnoreParens())) {
2497 D = CE->getMethodDecl();
2508 if (IsRelatedToDecl) {
2509 assert(!SuggestSuggestions &&
2510 "Variables blamed for unsafe buffer usage without suggestions!");
2511 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2514 S.Diag(Loc, diag::warn_unsafe_buffer_operation)
2515 << MsgParam << D <<
Range;
2517 S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam <<
Range;
2519 if (SuggestSuggestions) {
2520 S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled);
2525 void handleUnsafeLibcCall(
const CallExpr *
Call,
unsigned PrintfInfo,
2527 const Expr *UnsafeArg =
nullptr)
override {
2528 S.Diag(
Call->getBeginLoc(), diag::warn_unsafe_buffer_libc_call)
2529 <<
Call->getDirectCallee()
2531 if (PrintfInfo > 0) {
2533 UnsafeArg ? UnsafeArg->getSourceRange() :
Call->getSourceRange();
2534 S.Diag(R.
getBegin(), diag::note_unsafe_buffer_printf_call)
2539 void handleUnsafeOperationInContainer(
const Stmt *Operation,
2540 bool IsRelatedToDecl,
2541 ASTContext &Ctx)
override {
2544 unsigned MsgParam = 0;
2549 Loc = CtorExpr->getLocation();
2551 S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container);
2552 if (IsRelatedToDecl) {
2553 assert(!SuggestSuggestions &&
2554 "Variables blamed for unsafe buffer usage without suggestions!");
2555 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2559 void handleUnsafeVariableGroup(
const VarDecl *Variable,
2560 const VariableGroupsManager &VarGrpMgr,
2561 FixItList &&Fixes,
const Decl *D,
2562 const FixitStrategy &VarTargetTypes)
override {
2563 assert(!SuggestSuggestions &&
2564 "Unsafe buffer usage fixits displayed without suggestions!");
2565 S.Diag(
Variable->getLocation(), diag::warn_unsafe_buffer_variable)
2568 if (!Fixes.empty()) {
2570 "Fix-its are generated only for `NamedDecl`s");
2572 bool BriefMsg =
false;
2576 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Variable, &BriefMsg);
2577 unsigned FixItStrategy = 0;
2578 switch (VarTargetTypes.
lookup(Variable)) {
2586 assert(
false &&
"We support only std::span and std::array");
2591 BriefMsg ? diag::note_unsafe_buffer_variable_fixit_together
2592 : diag::note_unsafe_buffer_variable_fixit_group);
2595 FD << listVariableGroupAsString(Variable, VarGroupForVD)
2596 << (VarGroupForVD.size() > 1) << ND;
2597 for (
const auto &F : Fixes) {
2603 if (areDebugNotesRequested())
2604 for (
const DebugNote &
Note: DebugNotesByVar[Variable])
2605 S.Diag(
Note.first, diag::note_safe_buffer_debug_mode) <<
Note.second;
2609 bool isSafeBufferOptOut(
const SourceLocation &Loc)
const override {
2610 return S.PP.isSafeBufferOptOut(S.getSourceManager(), Loc);
2614 return S.Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container, Loc);
2617 bool ignoreUnsafeBufferInLibcCall(
const SourceLocation &Loc)
const override {
2618 return S.Diags.isIgnored(diag::warn_unsafe_buffer_libc_call, Loc);
2625 getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,
2626 StringRef WSSuffix =
"")
const override {
2627 Preprocessor &PP = S.getPreprocessor();
2628 TokenValue ClangUnsafeBufferUsageTokens[] = {
2637 StringRef MacroName;
2641 if (MacroName.empty())
2642 MacroName =
"[[clang::unsafe_buffer_usage]]";
2643 return MacroName.str() + WSSuffix.str();
2654 enableCheckFallThrough = 1;
2655 enableCheckUnreachable = 0;
2656 enableThreadSafetyAnalysis = 0;
2657 enableConsumedAnalysis = 0;
2678template <
typename... Ts>
2681 return (!D.
isIgnored(Diags, Loc) || ...);
2686 NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),
2687 MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),
2688 NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
2689 NumUninitAnalysisBlockVisits(0),
2690 MaxUninitAnalysisBlockVisitsPerFunction(0) {
2698 using namespace diag;
2704 P.enableCheckUnreachable =
2705 PolicyOverrides.enableCheckUnreachable ||
2706 areAnyEnabled(D, Loc, warn_unreachable, warn_unreachable_break,
2707 warn_unreachable_return, warn_unreachable_loop_increment);
2709 P.enableThreadSafetyAnalysis = PolicyOverrides.enableThreadSafetyAnalysis ||
2712 P.enableConsumedAnalysis = PolicyOverrides.enableConsumedAnalysis ||
2717void sema::AnalysisBasedWarnings::clearOverrides() {
2718 PolicyOverrides.enableCheckUnreachable =
false;
2719 PolicyOverrides.enableConsumedAnalysis =
false;
2720 PolicyOverrides.enableThreadSafetyAnalysis =
false;
2725 S.
Diag(D.Loc, D.PD);
2732 llvm::function_ref<void(
const Decl *)> Callback;
2733 const Module *
const TUModule;
2737 const Module *
const TUModule)
2738 : Callback(Callback), TUModule(TUModule) {
2783namespace clang::lifetimes {
2785class LifetimeSafetyReporterImpl :
public LifetimeSafetyReporter {
2788 LifetimeSafetyReporterImpl(Sema &S) : S(S) {}
2790 void reportUseAfterFree(
const Expr *IssueExpr,
const Expr *UseExpr,
2791 SourceLocation FreeLoc, Confidence
C)
override {
2793 C == Confidence::Definite
2794 ? diag::warn_lifetime_safety_loan_expires_permissive
2795 : diag::warn_lifetime_safety_loan_expires_strict)
2797 S.
Diag(FreeLoc, diag::note_lifetime_safety_destroyed_here);
2798 S.
Diag(UseExpr->
getExprLoc(), diag::note_lifetime_safety_used_here)
2822 bool UnsafeBufferUsageCanEmitSuggestions = S.getLangOpts().CPlusPlus20;
2823 bool UnsafeBufferUsageShouldEmitSuggestions =
2824 UnsafeBufferUsageCanEmitSuggestions &&
2825 DiagOpts.ShowSafeBufferUsageSuggestions;
2826 bool UnsafeBufferUsageShouldSuggestSuggestions =
2827 UnsafeBufferUsageCanEmitSuggestions &&
2828 !DiagOpts.ShowSafeBufferUsageSuggestions;
2829 UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions);
2832 auto CallAnalyzers = [&](
const Decl *Node) ->
void {
2833 if (Node->hasAttr<UnsafeBufferUsageAttr>())
2837 if (!Diags.
isIgnored(diag::warn_unsafe_buffer_operation,
2838 Node->getBeginLoc()) ||
2839 !Diags.
isIgnored(diag::warn_unsafe_buffer_variable,
2840 Node->getBeginLoc()) ||
2841 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2842 Node->getBeginLoc()) ||
2843 !Diags.
isIgnored(diag::warn_unsafe_buffer_libc_call,
2844 Node->getBeginLoc())) {
2846 UnsafeBufferUsageShouldEmitSuggestions);
2855 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2858 S.getLangOpts().CPlusPlus )) {
2860 .TraverseTranslationUnitDecl(TU);
2886 if (S.hasUncompilableErrorOccurred()) {
2908 bool EnableLifetimeSafetyAnalysis = S.getLangOpts().EnableLifetimeSafety;
2916 if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||
2917 P.enableConsumedAnalysis || EnableLifetimeSafetyAnalysis) {
2932 std::optional<LogicalErrorHandler> LEH;
2933 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->
getBeginLoc())) {
2940 bool analyzed =
false;
2944 for (
const Stmt *S : D.Stmts)
2951 bool AllReachable =
true;
2952 for (
const Stmt *S : D.Stmts) {
2962 AllReachable =
false;
2971 S.Diag(D.Loc, D.PD);
2980 if (P.enableCheckFallThrough) {
2981 const CheckFallThroughDiagnostics &CD =
2986 ? CheckFallThroughDiagnostics::MakeForLambda()
2988 ? CheckFallThroughDiagnostics::MakeForCoroutine(D)
2989 : CheckFallThroughDiagnostics::MakeForFunction(S, D)));
2994 if (P.enableCheckUnreachable) {
3007 if (P.enableThreadSafetyAnalysis) {
3010 threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
3012 Reporter.setIssueBetaWarnings(
true);
3014 Reporter.setVerbose(
true);
3017 &S.ThreadSafetyDeclCache);
3018 Reporter.emitDiagnostics();
3022 if (P.enableConsumedAnalysis) {
3023 consumed::ConsumedWarningsHandler WarningHandler(S);
3034 UninitValsDiagReporter reporter(S);
3041 ++NumUninitAnalysisFunctions;
3044 MaxUninitAnalysisVariablesPerFunction =
3045 std::max(MaxUninitAnalysisVariablesPerFunction,
3047 MaxUninitAnalysisBlockVisitsPerFunction =
3048 std::max(MaxUninitAnalysisBlockVisitsPerFunction,
3056 if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {
3058 lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);
3063 if (S.getLangOpts().ObjC && !S.getLangOpts().CPlusPlus &&
3064 shouldAnalyzeCalledOnceParameters(Diags, D->
getBeginLoc())) {
3066 CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);
3069 shouldAnalyzeCalledOnceConventions(Diags, D->
getBeginLoc()));
3073 bool FallThroughDiagFull =
3075 bool FallThroughDiagPerFunction = !Diags.
isIgnored(
3076 diag::warn_unannotated_fallthrough_per_function, D->
getBeginLoc());
3077 if (FallThroughDiagFull || FallThroughDiagPerFunction ||
3082 if (S.getLangOpts().ObjCWeak &&
3088 if (!Diags.
isIgnored(diag::warn_infinite_recursive_function,
3090 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
3097 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
3103 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->
getBeginLoc())) {
3112 ++NumFunctionsAnalyzed;
3116 NumCFGBlocks += cfg->getNumBlockIDs();
3117 MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
3118 cfg->getNumBlockIDs());
3120 ++NumFunctionsWithBadCFGs;
3126 llvm::errs() <<
"\n*** Analysis Based Warnings Stats:\n";
3128 unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
3129 unsigned AvgCFGBlocksPerFunction =
3130 !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
3131 llvm::errs() << NumFunctionsAnalyzed <<
" functions analyzed ("
3132 << NumFunctionsWithBadCFGs <<
" w/o CFGs).\n"
3133 <<
" " << NumCFGBlocks <<
" CFG blocks built.\n"
3134 <<
" " << AvgCFGBlocksPerFunction
3135 <<
" average CFG blocks per function.\n"
3136 <<
" " << MaxCFGBlocksPerFunction
3137 <<
" max CFG blocks per function.\n";
3139 unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
3140 : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
3141 unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
3142 : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
3143 llvm::errs() << NumUninitAnalysisFunctions
3144 <<
" functions analyzed for uninitialiazed variables\n"
3145 <<
" " << NumUninitAnalysisVariables <<
" variables analyzed.\n"
3146 <<
" " << AvgUninitVariablesPerFunction
3147 <<
" average variables per function.\n"
3148 <<
" " << MaxUninitAnalysisVariablesPerFunction
3149 <<
" max variables per function.\n"
3150 <<
" " << NumUninitAnalysisBlockVisits <<
" block visits.\n"
3151 <<
" " << AvgUninitBlockVisitsPerFunction
3152 <<
" average block visits per function.\n"
3153 <<
" " << MaxUninitAnalysisBlockVisitsPerFunction
3154 <<
" max block visits per function.\n";
static void visitReachableThrows(CFG *BodyCFG, llvm::function_ref< void(const CXXThrowExpr *, CFGBlock &)> Visit)
static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD)
static bool isReferenceToNoReturn(const Expr *E)
Checks if the given expression is a reference to a function with 'noreturn' attribute.
static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM, const Stmt *S)
static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC)
CheckFallThrough - Check that we don't fall off the end of a Statement that should return a value.
static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, QualType BlockType, const CheckFallThroughDiagnostics &CD, AnalysisDeclContext &AC)
CheckFallThroughForBody - Check that we don't fall off the end of a function that should return a val...
static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope)
static void diagnoseRepeatedUseOfWeak(Sema &S, const sema::FunctionScopeInfo *CurFn, const Decl *D, const ParentMap &PM)
static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, const FunctionDecl *FD)
static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, bool PerFunction)
static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, AnalysisDeclContext &AC)
static void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then, const Stmt *Else, bool CondVal, FixItHint &Fixit1, FixItHint &Fixit2)
Create a fixit to remove an if-like statement, on the assumption that its condition is CondVal.
static StringRef getFallthroughAttrSpelling(Preprocessor &PP, SourceLocation Loc)
static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, const UninitUse &Use, bool alwaysReportSelfInit=false)
DiagnoseUninitializedUse β Helper function for diagnosing uses of an uninitialized variable.
static bool areAnyEnabled(DiagnosticsEngine &D, SourceLocation Loc, Ts... Diags)
static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block)
static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock, CFG *Body)
Determine whether an exception thrown by E, unwinding from ThrowBlock, can reach ExitBlock.
static bool areAllValuesNoReturn(const VarDecl *VD, const CFGBlock &VarBlk, AnalysisDeclContext &AC)
static bool isNoexcept(const FunctionDecl *FD)
static bool DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD, const UninitUse &Use)
Diagnose uninitialized const reference usages.
static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, bool IsCapturedByBlock)
DiagUninitUse β Helper function to produce a diagnostic for an uninitialized use of a variable.
static bool DiagnoseUninitializedConstPtrUse(Sema &S, const VarDecl *VD, const UninitUse &Use)
Diagnose uninitialized const pointer usages.
static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC)
CheckUnreachable - Check for unreachable code.
@ NeverFallThroughOrReturn
static bool isInitializedWithNoReturn(const VarDecl *VD)
Checks if the given variable, which is assumed to be a function pointer, is initialized with a functi...
static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, const Stmt *Body, AnalysisDeclContext &AC)
static bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg)
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
Defines the Diagnostic-related interfaces.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
static bool EvaluateAsInt(const Expr *E, Expr::EvalResult &ExprResult, const ASTContext &Ctx, Expr::SideEffectsKind AllowSideEffects, EvalInfo &Info)
static std::pair< const Stmt *, const CFGBlock * > getLastStmt(const ExplodedNode *Node)
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)
const CFGBlock * getBlockForRegisteredExpression(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...
bool isReachable(const CFGBlock *Src, const CFGBlock *Dst)
Returns true if the block 'Dst' can be reached from block 'Src'.
const Stmt * getStmt() const
bool PruneTriviallyFalseEdges
bool AddCXXDefaultInitExprInCtors
BuildOptions & setAllAlwaysAdd()
BuildOptions & setAlwaysAdd(Stmt::StmtClass stmtClass, bool val=true)
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Represents a call to a member function that may be written either with member call syntax (e....
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
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()
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
bool isFunctionOrMethod() const
A reference to a declared variable, function, enum, etc.
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
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, bool DeferHint=false)
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 IssueWarnings(Policy P, FunctionScopeInfo *fscope, const Decl *D, QualType BlockType)
AnalysisBasedWarnings(Sema &s)
Policy getPolicyInEffectAt(SourceLocation Loc)
Represents a simple identification of a weak object.
Retains information about a function, method, or block that is currently being parsed.
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