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/StringRef.h"
59#include "llvm/Support/Debug.h"
60#include "llvm/Support/TimeProfiler.h"
75 SourceRange PreviousSilenceableCondVal;
78 UnreachableCodeHandler(Sema &
s) : S(
s) {}
81 SourceRange SilenceableCondVal, SourceRange R1,
82 SourceRange R2,
bool HasFallThroughAttr)
override {
86 if (HasFallThroughAttr &&
87 !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr,
93 if (PreviousSilenceableCondVal.isValid() &&
95 PreviousSilenceableCondVal == SilenceableCondVal)
97 PreviousSilenceableCondVal = SilenceableCondVal;
99 unsigned diag = diag::warn_unreachable;
102 diag = diag::warn_unreachable_break;
105 diag = diag::warn_unreachable_return;
108 diag = diag::warn_unreachable_loop_increment;
114 S.Diag(L, diag) << R1 << R2;
117 if (
Open.isValid()) {
118 SourceLocation Close = SilenceableCondVal.
getEnd();
119 Close = S.getLocForEndOfToken(Close);
121 S.Diag(
Open, diag::note_unreachable_silence)
142 UnreachableCodeHandler UC(S);
152 LogicalErrorHandler(Sema &S) : S(S) {}
154 static bool HasMacroID(
const Expr *E) {
159 for (
const Stmt *SubStmt : E->
children())
160 if (
const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt))
161 if (HasMacroID(SubExpr))
167 void logicAlwaysTrue(
const BinaryOperator *B,
bool isAlwaysTrue)
override {
171 unsigned DiagID = isAlwaysTrue
172 ? diag::warn_tautological_negation_or_compare
173 : diag::warn_tautological_negation_and_compare;
178 void compareAlwaysTrue(
const BinaryOperator *B,
179 bool isAlwaysTrueOrFalse)
override {
184 S.Diag(B->
getExprLoc(), diag::warn_tautological_overlap_comparison)
185 << DiagRange << isAlwaysTrueOrFalse;
188 void compareBitwiseEquality(
const BinaryOperator *B,
189 bool isAlwaysTrue)
override {
194 S.Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_always)
195 << DiagRange << isAlwaysTrue;
198 void compareBitwiseOr(
const BinaryOperator *B)
override {
203 S.Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;
206 static bool hasActiveDiagnostics(DiagnosticsEngine &Diags,
207 SourceLocation Loc) {
208 return !Diags.
isIgnored(diag::warn_tautological_overlap_comparison, Loc) ||
209 !Diags.
isIgnored(diag::warn_comparison_bitwise_or, Loc) ||
210 !Diags.
isIgnored(diag::warn_tautological_negation_and_compare, Loc);
224 for (
const auto &B :
Block) {
238 if (isa_and_nonnull<TemplateSpecializationType>(NNS.getAsType()))
254 bool foundRecursion =
false;
259 WorkList.push_back(&cfg->
getEntry());
261 while (!WorkList.empty()) {
264 for (
auto I =
Block->succ_begin(), E =
Block->succ_end(); I != E; ++I) {
266 if (!Visited.insert(SuccBlock).second)
270 if (ExitID == SuccBlock->getBlockID())
275 foundRecursion =
true;
279 WorkList.push_back(SuccBlock);
283 return foundRecursion;
319 Stack.push_back(&ThrowBlock);
322 while (!Stack.empty()) {
323 CFGBlock &UnwindBlock = *Stack.pop_back_val();
325 for (
auto &Succ : UnwindBlock.
succs()) {
326 if (!Succ.isReachable() || Queued[Succ->getBlockID()])
333 dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
334 QualType Caught = Catch->getCaughtType();
341 Stack.push_back(Succ);
342 Queued[Succ->getBlockID()] =
true;
356 if (!Reachable[B->getBlockID()])
359 std::optional<CFGStmt> S = E.getAs<
CFGStmt>();
362 if (
auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))
372 S.
Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
378 getAs<FunctionProtoType>())
403 if (FPT->isNothrow() || FD->
hasAttr<NoThrowAttr>())
412 if (
auto *FD = dyn_cast<FunctionDecl>(DRef->getDecl()))
413 return FD->isNoReturn();
432struct TransferFunctions :
public StmtVisitor<TransferFunctions> {
434 std::optional<bool> AllValuesAreNoReturn;
436 TransferFunctions(
const VarDecl *VD) : Var(VD) {}
438 void reset() { AllValuesAreNoReturn = std::nullopt; }
440 void VisitDeclStmt(DeclStmt *DS) {
441 for (
auto *DI : DS->
decls())
442 if (
auto *VD = dyn_cast<VarDecl>(DI))
443 if (VarDecl *Def = VD->getDefinition())
448 void VisitUnaryOperator(UnaryOperator *UO) {
452 if (DRef->getDecl() == Var)
453 AllValuesAreNoReturn =
false;
457 void VisitBinaryOperator(BinaryOperator *BO) {
460 if (DRef->getDecl() == Var)
464 void VisitCallExpr(CallExpr *CE) {
467 const Expr *Arg = *I;
470 if (
auto VD = dyn_cast<VarDecl>(DRef->getDecl()))
471 if (VD->getDefinition() == Var)
472 AllValuesAreNoReturn =
false;
498 using MapTy = llvm::DenseMap<const CFGBlock *, std::optional<bool>>;
499 using ValueTy = MapTy::value_type;
501 BlocksToCheck[&VarBlk] = std::nullopt;
502 const auto BlockSatisfiesCondition = [](ValueTy Item) {
503 return Item.getSecond().value_or(
false);
506 TransferFunctions TF(VD);
508 llvm::DenseSet<const CFGBlock *> Visited;
511 if (Visited.contains(B))
517 if (std::optional<CFGStmt> cs = ri->getAs<
CFGStmt>()) {
518 const Stmt *S = cs->getStmt();
520 TF.Visit(
const_cast<Stmt *
>(S));
521 if (TF.AllValuesAreNoReturn) {
522 if (!TF.AllValuesAreNoReturn.value())
524 BlocksToCheck[B] =
true;
531 if (llvm::all_of(BlocksToCheck, BlockSatisfiesCondition))
536 if (!BlocksToCheck[B]) {
538 BlocksToCheck.erase(B);
539 for (
const auto &PredBlk : B->preds())
540 if (!BlocksToCheck.contains(PredBlk))
541 BlocksToCheck[PredBlk] = std::nullopt;
584 for (
const auto *B : *cfg) {
585 if (!live[B->getBlockID()]) {
586 if (B->preds().empty()) {
587 const Stmt *Term = B->getTerminatorStmt();
588 if (isa_and_nonnull<CXXTryStmt>(Term))
600 bool HasLiveReturn =
false;
601 bool HasFakeEdge =
false;
602 bool HasPlainEdge =
false;
603 bool HasAbnormalEdge =
false;
621 HasAbnormalEdge =
true;
630 for ( ; ri != re ; ++ri)
638 HasAbnormalEdge =
true;
649 HasLiveReturn =
true;
663 HasLiveReturn =
true;
667 HasAbnormalEdge =
true;
671 HasAbnormalEdge =
true;
674 if (
auto *
Call = dyn_cast<CallExpr>(S)) {
675 const Expr *Callee =
Call->getCallee();
676 if (Callee->getType()->isPointerType())
678 dyn_cast<DeclRefExpr>(Callee->IgnoreParenImpCasts()))
679 if (
auto *VD = dyn_cast<VarDecl>(DeclRef->getDecl()))
681 HasAbnormalEdge =
true;
693 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
703struct CheckFallThroughDiagnostics {
704 unsigned diag_FallThrough_HasNoReturn = 0;
705 unsigned diag_FallThrough_ReturnsNonVoid = 0;
706 unsigned diag_NeverFallThroughOrReturn = 0;
708 SourceLocation FuncLoc;
710 static CheckFallThroughDiagnostics MakeForFunction(Sema &S,
712 CheckFallThroughDiagnostics D;
713 D.FuncLoc =
Func->getLocation();
714 D.diag_FallThrough_HasNoReturn = diag::warn_noreturn_has_return_expr;
715 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
719 bool isVirtualMethod =
false;
720 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(
Func))
721 isVirtualMethod =
Method->isVirtual();
725 if (
const FunctionDecl *
Function = dyn_cast<FunctionDecl>(
Func)) {
729 D.diag_FallThrough_ReturnsNonVoid = diag::ext_main_no_return;
734 D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function;
736 D.FunKind = diag::FalloffFunctionKind::Function;
740 static CheckFallThroughDiagnostics MakeForCoroutine(
const Decl *
Func) {
741 CheckFallThroughDiagnostics D;
742 D.FuncLoc =
Func->getLocation();
743 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
744 D.FunKind = diag::FalloffFunctionKind::Coroutine;
748 static CheckFallThroughDiagnostics MakeForBlock() {
749 CheckFallThroughDiagnostics D;
750 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;
751 D.diag_FallThrough_ReturnsNonVoid = diag::err_falloff_nonvoid;
752 D.FunKind = diag::FalloffFunctionKind::Block;
756 static CheckFallThroughDiagnostics MakeForLambda() {
757 CheckFallThroughDiagnostics D;
758 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;
759 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
760 D.FunKind = diag::FalloffFunctionKind::Lambda;
764 bool checkDiagnostics(DiagnosticsEngine &D,
bool ReturnsVoid,
765 bool HasNoReturn)
const {
766 if (FunKind == diag::FalloffFunctionKind::Function) {
767 return (ReturnsVoid ||
768 D.
isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&
770 D.
isIgnored(diag::warn_noreturn_has_return_expr, FuncLoc)) &&
772 D.
isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));
774 if (FunKind == diag::FalloffFunctionKind::Coroutine) {
775 return (ReturnsVoid ||
776 D.
isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&
780 return ReturnsVoid && !HasNoReturn;
792 const CheckFallThroughDiagnostics &CD,
795 bool ReturnsVoid =
false;
796 bool HasNoReturn =
false;
798 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
799 if (
const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
800 ReturnsVoid = CBody->getFallthroughHandler() !=
nullptr;
802 ReturnsVoid = FD->getReturnType()->isVoidType();
803 HasNoReturn = FD->isNoReturn() || FD->hasAttr<InferredNoReturnAttr>();
805 else if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
806 ReturnsVoid = MD->getReturnType()->isVoidType();
807 HasNoReturn = MD->hasAttr<NoReturnAttr>();
812 if (FT->getReturnType()->isVoidType())
814 if (FT->getNoReturnAttr())
822 if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
838 if (CD.diag_FallThrough_HasNoReturn)
839 S.
Diag(RBrace, CD.diag_FallThrough_HasNoReturn) << CD.FunKind;
840 }
else if (!ReturnsVoid && CD.diag_FallThrough_ReturnsNonVoid) {
844 if (
const auto *CS = dyn_cast<CompoundStmt>(Body);
845 CS && !CS->body_empty()) {
846 const Stmt *LastStmt = CS->body_back();
848 if (
const auto *EWC = dyn_cast<ExprWithCleanups>(LastStmt)) {
849 LastStmt = EWC->getSubExpr();
851 if (
const auto *CE = dyn_cast<CallExpr>(LastStmt)) {
853 Callee && Callee->hasAttr<InferredNoReturnAttr>()) {
864 S.
Diag(RBrace, CD.diag_FallThrough_ReturnsNonVoid)
865 << CD.FunKind << NotInAllControlPaths;
869 if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
870 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
871 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
872 }
else if (
const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
873 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
875 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
894 const DeclRefExpr *Needle;
897 typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited;
899 ContainsReference(ASTContext &Context,
const DeclRefExpr *Needle)
900 : Inherited(Context), FoundReference(
false), Needle(Needle) {}
902 void VisitExpr(
const Expr *E) {
907 Inherited::VisitExpr(E);
910 void VisitDeclRefExpr(
const DeclRefExpr *E) {
912 FoundReference =
true;
917 bool doesContainReference()
const {
return FoundReference; }
925 S.
Diag(VD->
getLocation(), diag::note_block_var_fixit_add_initialization)
946 S.
Diag(Loc, diag::note_var_fixit_add_initialization) << VD->
getDeclName()
954 const Stmt *Else,
bool CondVal,
978 bool IsCapturedByBlock) {
979 bool Diagnosed =
false;
1011 const Stmt *Term = I->Terminator;
1021 int RemoveDiagKind = -1;
1022 const char *FixitStr =
1023 S.
getLangOpts().CPlusPlus ? (I->Output ?
"true" :
"false")
1024 : (I->Output ?
"1" :
"0");
1027 switch (Term ? Term->
getStmtClass() : Stmt::DeclStmtClass) {
1034 case Stmt::IfStmtClass: {
1041 I->Output, Fixit1, Fixit2);
1044 case Stmt::ConditionalOperatorClass: {
1051 I->Output, Fixit1, Fixit2);
1054 case Stmt::BinaryOperatorClass: {
1062 if ((BO->
getOpcode() == BO_LAnd && I->Output) ||
1063 (BO->
getOpcode() == BO_LOr && !I->Output))
1074 case Stmt::WhileStmtClass:
1081 case Stmt::ForStmtClass:
1091 case Stmt::CXXForRangeStmtClass:
1092 if (I->Output == 1) {
1104 case Stmt::DoStmtClass:
1107 Range =
cast<DoStmt>(Term)->getCond()->getSourceRange();
1113 case Stmt::CaseStmtClass:
1118 case Stmt::DefaultStmtClass:
1125 S.
Diag(Range.getBegin(), diag::warn_sometimes_uninit_var)
1126 << VD->
getDeclName() << IsCapturedByBlock << DiagKind
1127 << Str << I->Output << Range;
1130 if (RemoveDiagKind != -1)
1132 << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
1166 bool alwaysReportSelfInit =
false) {
1180 if (!alwaysReportSelfInit && DRE ==
Initializer->IgnoreParenImpCasts())
1183 ContainsReference CR(S.
Context, DRE);
1185 if (CR.doesContainReference()) {
1186 S.
Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
1197 diag::warn_uninit_byref_blockvar_captured_by_block)
1217 FallthroughMapper(Sema &S) : FoundSwitchStatements(
false), S(S) {
1218 ShouldWalkTypesOfTypeLocs =
false;
1221 bool foundSwitchStatements()
const {
return FoundSwitchStatements; }
1223 void markFallthroughVisited(
const AttributedStmt *Stmt) {
1224 bool Found = FallthroughStmts.erase(Stmt);
1229 typedef llvm::SmallPtrSet<const AttributedStmt *, 8> AttrStmts;
1231 const AttrStmts &getFallthroughStmts()
const {
return FallthroughStmts; }
1233 void fillReachableBlocks(CFG *Cfg) {
1234 assert(ReachableBlocks.empty() &&
"ReachableBlocks already filled");
1235 std::deque<const CFGBlock *> BlockQueue;
1237 ReachableBlocks.insert(&Cfg->
getEntry());
1238 BlockQueue.push_back(&Cfg->
getEntry());
1243 for (
const auto *B : *Cfg) {
1244 const Stmt *L = B->getLabel();
1245 if (isa_and_nonnull<SwitchCase>(L) && ReachableBlocks.insert(B).second)
1246 BlockQueue.push_back(B);
1249 while (!BlockQueue.empty()) {
1250 const CFGBlock *P = BlockQueue.front();
1251 BlockQueue.pop_front();
1252 for (
const CFGBlock *B : P->
succs()) {
1253 if (B && ReachableBlocks.insert(B).second)
1254 BlockQueue.push_back(B);
1259 bool checkFallThroughIntoBlock(
const CFGBlock &B,
int &AnnotatedCnt,
1260 bool IsTemplateInstantiation) {
1261 assert(!ReachableBlocks.empty() &&
"ReachableBlocks empty");
1263 int UnannotatedCnt = 0;
1267 while (!BlockQueue.empty()) {
1268 const CFGBlock *P = BlockQueue.
front();
1269 BlockQueue.pop_front();
1274 if (isa_and_nonnull<SwitchStmt>(Term))
1277 const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->
getLabel());
1281 const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->
getLabel());
1285 if (!ReachableBlocks.count(P)) {
1286 for (
const CFGElement &Elem : llvm::reverse(*P)) {
1287 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) {
1288 if (
const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
1292 if (!IsTemplateInstantiation)
1293 S.Diag(AS->getBeginLoc(),
1294 diag::warn_unreachable_fallthrough_attr);
1295 markFallthroughVisited(AS);
1314 if (
const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {
1315 markFallthroughVisited(AS);
1323 std::back_inserter(BlockQueue));
1329 return !!UnannotatedCnt;
1332 bool VisitAttributedStmt(AttributedStmt *S)
override {
1333 if (asFallThroughAttr(S))
1334 FallthroughStmts.insert(S);
1338 bool VisitSwitchStmt(SwitchStmt *S)
override {
1339 FoundSwitchStatements =
true;
1345 bool TraverseDecl(Decl *D)
override {
return true; }
1348 bool TraverseLambdaExpr(
LambdaExpr *LE)
override {
1350 for (
const auto C : zip(
LE->captures(),
LE->capture_inits()))
1351 TraverseLambdaCapture(LE, &std::get<0>(
C), std::get<1>(
C));
1357 static const AttributedStmt *asFallThroughAttr(
const Stmt *S) {
1358 if (
const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
1365 static const Stmt *
getLastStmt(
const CFGBlock &B) {
1368 for (
const CFGElement &Elem : llvm::reverse(B))
1369 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
1370 return CS->getStmt();
1374 if (
const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.
getLabel()))
1381 bool FoundSwitchStatements;
1382 AttrStmts FallthroughStmts;
1384 llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
1391 tok::l_square, tok::l_square,
1393 tok::r_square, tok::r_square
1399 tok::r_square, tok::r_square
1404 StringRef MacroName;
1405 if (PreferClangAttr)
1407 if (MacroName.empty())
1409 if (MacroName.empty() && !PreferClangAttr)
1411 if (MacroName.empty()) {
1412 if (!PreferClangAttr)
1413 MacroName =
"[[fallthrough]]";
1415 MacroName =
"[[clang::fallthrough]]";
1417 MacroName =
"__attribute__((fallthrough))";
1424 FallthroughMapper FM(S);
1425 FM.TraverseStmt(AC.
getBody());
1427 if (!FM.foundSwitchStatements())
1430 if (PerFunction && FM.getFallthroughStmts().empty())
1438 FM.fillReachableBlocks(Cfg);
1440 for (
const CFGBlock *B : llvm::reverse(*Cfg)) {
1443 if (!isa_and_nonnull<SwitchCase>(Label))
1448 bool IsTemplateInstantiation =
false;
1450 IsTemplateInstantiation = Function->isTemplateInstantiation();
1451 if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,
1452 IsTemplateInstantiation))
1456 PerFunction ? diag::warn_unannotated_fallthrough_per_function
1457 : diag::warn_unannotated_fallthrough);
1459 if (!AnnotatedCnt) {
1470 if (!(B->
empty() && isa_and_nonnull<BreakStmt>(Term))) {
1474 TextToInsert +=
"; ";
1475 S.
Diag(L, diag::note_insert_fallthrough_fixit)
1476 << AnnotationSpelling
1479 S.
Diag(L, diag::note_insert_break_fixit)
1484 for (
const auto *F : FM.getFallthroughStmts())
1485 S.
Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement);
1494 case Stmt::ForStmtClass:
1495 case Stmt::WhileStmtClass:
1496 case Stmt::CXXForRangeStmtClass:
1497 case Stmt::ObjCForCollectionStmtClass:
1499 case Stmt::DoStmtClass: {
1503 return Result.
Val.
getInt().getBoolValue();
1520 typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
1529 for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end();
1531 const WeakUseVector &Uses = I->second;
1534 WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
1535 for ( ; UI != UE; ++UI) {
1548 if (UI == Uses.begin()) {
1549 WeakUseVector::const_iterator UI2 = UI;
1550 for (++UI2; UI2 != UE; ++UI2)
1551 if (UI2->isUnsafe())
1555 if (!
isInLoop(Ctx, PM, UI->getUseExpr()))
1558 const WeakObjectProfileTy &Profile = I->first;
1559 if (!Profile.isExactProfile())
1564 Base = Profile.getProperty();
1565 assert(
Base &&
"A profile always has a base or property.");
1567 if (
const VarDecl *BaseVar = dyn_cast<VarDecl>(
Base))
1573 UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
1576 if (UsesByStmt.empty())
1581 llvm::sort(UsesByStmt,
1582 [&
SM](
const StmtUsesPair &LHS,
const StmtUsesPair &RHS) {
1583 return SM.isBeforeInTranslationUnit(LHS.first->getBeginLoc(),
1584 RHS.first->getBeginLoc());
1600 FunctionKind =
Block;
1602 FunctionKind = Lambda;
1604 FunctionKind = Method;
1606 FunctionKind = Function;
1609 for (
const auto &P : UsesByStmt) {
1610 const Stmt *FirstRead = P.first;
1611 const WeakObjectProfileTy &Key = P.second->first;
1612 const WeakUseVector &Uses = P.second->second;
1620 if (Key.isExactProfile())
1621 DiagKind = diag::warn_arc_repeated_use_of_weak;
1623 DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
1635 const NamedDecl *KeyProp = Key.getProperty();
1637 ObjectKind = Variable;
1639 ObjectKind = Property;
1641 ObjectKind = ImplicitProperty;
1645 llvm_unreachable(
"Unexpected weak object kind!");
1650 if (Prop->hasAttr<IBOutletAttr>())
1655 <<
int(ObjectKind) << KeyProp <<
int(FunctionKind)
1659 for (
const auto &Use : Uses) {
1660 if (Use.getUseExpr() == FirstRead)
1662 S.
Diag(Use.getUseExpr()->getBeginLoc(),
1663 diag::note_arc_weak_also_accessed_here)
1664 << Use.getUseExpr()->getSourceRange();
1672typedef std::pair<PartialDiagnosticAt, OptionalNotes>
DelayedDiag;
1673typedef std::list<DelayedDiag>
DiagList;
1675struct SortDiagBySourceLocation {
1677 SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {}
1679 bool operator()(
const DelayedDiag &left,
const DelayedDiag &right) {
1682 return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
1691 typedef SmallVector<UninitUse, 2> UsesVec;
1692 typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
1696 typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
1700 UninitValsDiagReporter(Sema &S) : S(S) {}
1703 MappedType &getUses(
const VarDecl *vd) {
1704 MappedType &
V = uses[vd];
1705 if (!
V.getPointer())
1706 V.setPointer(
new UsesVec());
1710 void handleUseOfUninitVariable(
const VarDecl *vd,
1711 const UninitUse &use)
override {
1712 getUses(vd).getPointer()->push_back(use);
1715 void handleSelfInit(
const VarDecl *vd)
override { getUses(vd).setInt(
true); }
1718 for (
const auto &P : uses) {
1719 const VarDecl *vd = P.first;
1720 const MappedType &
V = P.second;
1722 UsesVec *vec =
V.getPointer();
1723 bool hasSelfInit =
V.getInt();
1725 diagnoseUnitializedVar(vd, hasSelfInit, vec);
1735 static bool hasAlwaysUninitializedUse(
const UsesVec* vec) {
1736 return llvm::any_of(*vec, [](
const UninitUse &U) {
1746 void diagnoseUnitializedVar(
const VarDecl *vd,
bool hasSelfInit,
1751 if (hasSelfInit && hasAlwaysUninitializedUse(vec)) {
1762 llvm::sort(*vec, [](
const UninitUse &a,
const UninitUse &
b) {
1766 return b.isConstRefOrPtrUse();
1773 for (
const auto &U : *vec) {
1782 UninitUse Use = hasSelfInit ? UninitUse(U.
getUser(),
false) : U;
1791class CalledOnceInterProceduralData {
1794 void addDelayedWarning(
const BlockDecl *
Block,
1796 DelayedBlockWarnings[
Block].emplace_back(std::move(
Warning));
1799 void flushWarnings(
const BlockDecl *
Block, Sema &S) {
1801 S.
Diag(Delayed.first, Delayed.second);
1803 discardWarnings(
Block);
1806 void discardWarnings(
const BlockDecl *
Block) {
1807 DelayedBlockWarnings.erase(
Block);
1811 using DelayedDiagnostics = SmallVector<PartialDiagnosticAt, 2>;
1812 llvm::DenseMap<const BlockDecl *, DelayedDiagnostics> DelayedBlockWarnings;
1817 CalledOnceCheckReporter(Sema &S, CalledOnceInterProceduralData &Data)
1818 : S(S), Data(Data) {}
1819 void handleDoubleCall(
const ParmVarDecl *
Parameter,
const Expr *
Call,
1820 const Expr *PrevCall,
bool IsCompletionHandler,
1821 bool Poised)
override {
1822 auto DiagToReport = IsCompletionHandler
1823 ? diag::warn_completion_handler_called_twice
1824 : diag::warn_called_once_gets_called_twice;
1826 S.Diag(PrevCall->
getBeginLoc(), diag::note_called_once_gets_called_twice)
1830 void handleNeverCalled(
const ParmVarDecl *
Parameter,
1831 bool IsCompletionHandler)
override {
1832 auto DiagToReport = IsCompletionHandler
1833 ? diag::warn_completion_handler_never_called
1834 : diag::warn_called_once_never_called;
1835 S.Diag(
Parameter->getBeginLoc(), DiagToReport)
1841 bool IsCalledDirectly,
1842 bool IsCompletionHandler)
override {
1843 auto DiagToReport = IsCompletionHandler
1844 ? diag::warn_completion_handler_never_called_when
1845 : diag::warn_called_once_never_called_when;
1849 << (
unsigned)Reason);
1859 void handleCapturedNeverCalled(
const ParmVarDecl *
Parameter,
1861 bool IsCompletionHandler)
override {
1862 auto DiagToReport = IsCompletionHandler
1863 ? diag::warn_completion_handler_never_called
1864 : diag::warn_called_once_never_called;
1870 handleBlockThatIsGuaranteedToBeCalledOnce(
const BlockDecl *
Block)
override {
1871 Data.flushWarnings(
Block, S);
1874 void handleBlockWithNoGuarantees(
const BlockDecl *
Block)
override {
1875 Data.discardWarnings(
Block);
1880 CalledOnceInterProceduralData &Data;
1883constexpr unsigned CalledOnceWarnings[] = {
1884 diag::warn_called_once_never_called,
1885 diag::warn_called_once_never_called_when,
1886 diag::warn_called_once_gets_called_twice};
1888constexpr unsigned CompletionHandlerWarnings[]{
1889 diag::warn_completion_handler_never_called,
1890 diag::warn_completion_handler_never_called_when,
1891 diag::warn_completion_handler_called_twice};
1896 return llvm::any_of(DiagIDs, [&Diags, At](
unsigned DiagID) {
1903 return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);
1908 return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||
1909 shouldAnalyzeCalledOnceConventions(Diags, At);
1919class ThreadSafetyReporter :
public clang::threadSafety::ThreadSafetyHandler {
1922 SourceLocation FunLocation, FunEndLocation;
1924 const FunctionDecl *CurrentFunction;
1928 if (Verbose && CurrentFunction) {
1930 S.PDiag(diag::note_thread_warning_in_fun)
1931 << CurrentFunction);
1939 if (Verbose && CurrentFunction) {
1941 S.PDiag(diag::note_thread_warning_in_fun)
1942 << CurrentFunction);
1943 ONS.push_back(std::move(FNote));
1951 ONS.push_back(Note1);
1952 ONS.push_back(Note2);
1953 if (Verbose && CurrentFunction) {
1955 S.PDiag(diag::note_thread_warning_in_fun)
1956 << CurrentFunction);
1957 ONS.push_back(std::move(FNote));
1962 OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) {
1965 LocLocked, S.PDiag(diag::note_locked_here) << Kind))
1969 OptionalNotes makeUnlockedHereNote(SourceLocation LocUnlocked,
1973 LocUnlocked, S.PDiag(diag::note_unlocked_here) << Kind))
1977 OptionalNotes makeManagedMismatchNoteForParam(SourceLocation DeclLoc) {
1981 S.PDiag(diag::note_managed_mismatch_here_for_param)))
1986 ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
1987 : S(S), FunLocation(FL), FunEndLocation(FEL),
1990 void setVerbose(
bool b) { Verbose =
b; }
1997 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
1998 for (
const auto &
Diag : Warnings) {
1999 S.Diag(
Diag.first.first,
Diag.first.second);
2000 for (
const auto &
Note :
Diag.second)
2005 void handleUnmatchedUnderlyingMutexes(SourceLocation Loc, SourceLocation DLoc,
2006 Name scopeName, StringRef Kind,
2007 Name expected, Name actual)
override {
2009 S.PDiag(diag::warn_unmatched_underlying_mutexes)
2010 << Kind << scopeName << expected << actual);
2011 Warnings.emplace_back(std::move(
Warning),
2012 makeManagedMismatchNoteForParam(DLoc));
2015 void handleExpectMoreUnderlyingMutexes(SourceLocation Loc,
2016 SourceLocation DLoc, Name scopeName,
2018 Name expected)
override {
2020 Loc, S.PDiag(diag::warn_expect_more_underlying_mutexes)
2021 << Kind << scopeName << expected);
2022 Warnings.emplace_back(std::move(
Warning),
2023 makeManagedMismatchNoteForParam(DLoc));
2026 void handleExpectFewerUnderlyingMutexes(SourceLocation Loc,
2027 SourceLocation DLoc, Name scopeName,
2029 Name actual)
override {
2031 Loc, S.PDiag(diag::warn_expect_fewer_underlying_mutexes)
2032 << Kind << scopeName << actual);
2033 Warnings.emplace_back(std::move(
Warning),
2034 makeManagedMismatchNoteForParam(DLoc));
2037 void handleInvalidLockExp(SourceLocation Loc)
override {
2040 Warnings.emplace_back(std::move(
Warning), getNotes());
2043 void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc,
2044 SourceLocation LocPreviousUnlock)
override {
2048 << Kind << LockName);
2049 Warnings.emplace_back(std::move(
Warning),
2050 makeUnlockedHereNote(LocPreviousUnlock, Kind));
2053 void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
2055 SourceLocation LocLocked,
2056 SourceLocation LocUnlock)
override {
2058 LocUnlock = FunLocation;
2060 LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch)
2061 << Kind << LockName << Received << Expected);
2062 Warnings.emplace_back(std::move(
Warning),
2063 makeLockedHereNote(LocLocked, Kind));
2066 void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked,
2067 SourceLocation LocDoubleLock)
override {
2069 LocDoubleLock = FunLocation;
2071 << Kind << LockName);
2072 Warnings.emplace_back(std::move(
Warning),
2073 makeLockedHereNote(LocLocked, Kind));
2076 void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
2077 SourceLocation LocLocked,
2078 SourceLocation LocEndOfScope,
2080 bool ReentrancyMismatch)
override {
2081 unsigned DiagID = 0;
2084 DiagID = diag::warn_lock_some_predecessors;
2087 DiagID = diag::warn_expecting_lock_held_on_loop;
2090 DiagID = diag::warn_no_unlock;
2093 DiagID = diag::warn_expecting_locked;
2097 LocEndOfScope = FunEndLocation;
2101 << ReentrancyMismatch);
2102 Warnings.emplace_back(std::move(
Warning),
2103 makeLockedHereNote(LocLocked, Kind));
2106 void handleExclusiveAndShared(StringRef Kind, Name LockName,
2107 SourceLocation Loc1,
2108 SourceLocation Loc2)
override {
2110 S.PDiag(diag::warn_lock_exclusive_and_shared)
2111 << Kind << LockName);
2113 << Kind << LockName);
2114 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2118 AccessKind AK, SourceLocation Loc)
override {
2119 unsigned DiagID = 0;
2126 DiagID = diag::warn_variable_requires_any_lock;
2133 DiagID = diag::warn_var_deref_requires_any_lock;
2136 llvm_unreachable(
"Only works for variables");
2141 Warnings.emplace_back(std::move(
Warning), getNotes());
2144 void handleMutexNotHeld(StringRef Kind,
const NamedDecl *D,
2147 Name *PossibleMatch)
override {
2148 unsigned DiagID = 0;
2149 if (PossibleMatch) {
2152 DiagID = diag::warn_variable_requires_lock_precise;
2155 DiagID = diag::warn_var_deref_requires_lock_precise;
2158 DiagID = diag::warn_fun_requires_lock_precise;
2161 DiagID = diag::warn_guarded_pass_by_reference;
2164 DiagID = diag::warn_pt_guarded_pass_by_reference;
2167 DiagID = diag::warn_guarded_return_by_reference;
2170 DiagID = diag::warn_pt_guarded_return_by_reference;
2173 DiagID = diag::warn_guarded_pass_pointer;
2176 DiagID = diag::warn_pt_guarded_pass_pointer;
2179 DiagID = diag::warn_guarded_return_pointer;
2182 DiagID = diag::warn_pt_guarded_return_pointer;
2192 S.PDiag(diag::note_guarded_by_declared_here)
2194 Warnings.emplace_back(std::move(
Warning), getNotes(
Note, VNote));
2196 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2200 DiagID = diag::warn_variable_requires_lock;
2203 DiagID = diag::warn_var_deref_requires_lock;
2206 DiagID = diag::warn_fun_requires_lock;
2209 DiagID = diag::warn_guarded_pass_by_reference;
2212 DiagID = diag::warn_pt_guarded_pass_by_reference;
2215 DiagID = diag::warn_guarded_return_by_reference;
2218 DiagID = diag::warn_pt_guarded_return_by_reference;
2221 DiagID = diag::warn_guarded_pass_pointer;
2224 DiagID = diag::warn_pt_guarded_pass_pointer;
2227 DiagID = diag::warn_guarded_return_pointer;
2230 DiagID = diag::warn_pt_guarded_return_pointer;
2238 S.PDiag(diag::note_guarded_by_declared_here));
2239 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2241 Warnings.emplace_back(std::move(
Warning), getNotes());
2245 void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
2246 SourceLocation Loc)
override {
2248 S.PDiag(diag::warn_acquire_requires_negative_cap)
2249 << Kind << LockName << Neg);
2250 Warnings.emplace_back(std::move(
Warning), getNotes());
2253 void handleNegativeNotHeld(
const NamedDecl *D, Name LockName,
2254 SourceLocation Loc)
override {
2256 Loc, S.PDiag(diag::warn_fun_requires_negative_cap) << D << LockName);
2257 Warnings.emplace_back(std::move(
Warning), getNotes());
2260 void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
2261 SourceLocation Loc)
override {
2263 << Kind << FunName << LockName);
2264 Warnings.emplace_back(std::move(
Warning), getNotes());
2267 void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
2268 SourceLocation Loc)
override {
2270 S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
2271 Warnings.emplace_back(std::move(
Warning), getNotes());
2274 void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc)
override {
2276 S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
2277 Warnings.emplace_back(std::move(
Warning), getNotes());
2280 void enterFunction(
const FunctionDecl* FD)
override {
2281 CurrentFunction = FD;
2284 void leaveFunction(
const FunctionDecl* FD)
override {
2285 CurrentFunction =
nullptr;
2306 ConsumedWarningsHandler(Sema &S) : S(S) {}
2309 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
2310 for (
const auto &
Diag : Warnings) {
2311 S.Diag(
Diag.first.first,
Diag.first.second);
2312 for (
const auto &
Note :
Diag.second)
2317 void warnLoopStateMismatch(SourceLocation Loc,
2318 StringRef VariableName)
override {
2325 void warnParamReturnTypestateMismatch(SourceLocation Loc,
2326 StringRef VariableName,
2327 StringRef ExpectedState,
2328 StringRef ObservedState)
override {
2331 diag::warn_param_return_typestate_mismatch) << VariableName <<
2332 ExpectedState << ObservedState);
2337 void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
2338 StringRef ObservedState)
override {
2341 diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
2346 void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
2347 StringRef TypeName)
override {
2349 diag::warn_return_typestate_for_unconsumable_type) << TypeName);
2354 void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
2355 StringRef ObservedState)
override {
2358 diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
2363 void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
2364 SourceLocation Loc)
override {
2367 diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
2372 void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
2373 StringRef State, SourceLocation Loc)
override {
2376 MethodName << VariableName << State);
2392 bool SuggestSuggestions;
2396 std::string listVariableGroupAsString(
2397 const VarDecl *VD,
const ArrayRef<const VarDecl *> &VarGroupForVD)
const {
2398 if (VarGroupForVD.size() <= 1)
2401 std::vector<StringRef> VarNames;
2402 auto PutInQuotes = [](StringRef S) -> std::string {
2403 return "'" + S.str() +
"'";
2406 for (
auto *
V : VarGroupForVD) {
2409 VarNames.push_back(
V->getName());
2411 if (VarNames.size() == 1) {
2412 return PutInQuotes(VarNames[0]);
2414 if (VarNames.size() == 2) {
2415 return PutInQuotes(VarNames[0]) +
" and " + PutInQuotes(VarNames[1]);
2417 assert(VarGroupForVD.size() > 3);
2418 const unsigned N = VarNames.size() -
2420 std::string AllVars =
"";
2422 for (
unsigned I = 0; I < N; ++I)
2423 AllVars.append(PutInQuotes(VarNames[I]) +
", ");
2424 AllVars.append(PutInQuotes(VarNames[N]) +
", and " +
2425 PutInQuotes(VarNames[N + 1]));
2430 UnsafeBufferUsageReporter(Sema &S,
bool SuggestSuggestions)
2431 : S(S), SuggestSuggestions(SuggestSuggestions) {}
2433 void handleUnsafeOperation(
const Stmt *Operation,
bool IsRelatedToDecl,
2434 ASTContext &Ctx)
override {
2437 unsigned MsgParam = 0;
2438 NamedDecl *D =
nullptr;
2439 if (
const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
2440 Loc = ASE->getBase()->getExprLoc();
2441 Range = ASE->getBase()->getSourceRange();
2443 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
2445 if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
2446 Op == BO_SubAssign) {
2456 }
else if (
const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
2458 if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
2467 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2471 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2473 D = ME->getMemberDecl();
2475 }
else if (
const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) {
2476 QualType destType = ECE->getType();
2477 bool destTypeComplete =
true;
2483 destTypeComplete = D->isCompleteDefinition();
2487 if (destTypeComplete) {
2489 QualType srcType = ECE->getSubExpr()->getType();
2499 if (
const auto *CE = dyn_cast<CXXMemberCallExpr>(
2500 ECE->getSubExpr()->IgnoreParens())) {
2501 D = CE->getMethodDecl();
2512 if (IsRelatedToDecl) {
2513 assert(!SuggestSuggestions &&
2514 "Variables blamed for unsafe buffer usage without suggestions!");
2515 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2518 S.Diag(Loc, diag::warn_unsafe_buffer_operation)
2519 << MsgParam << D <<
Range;
2521 S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam <<
Range;
2523 if (SuggestSuggestions) {
2524 S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled);
2529 void handleUnsafeLibcCall(
const CallExpr *
Call,
unsigned PrintfInfo,
2531 const Expr *UnsafeArg =
nullptr)
override {
2532 unsigned DiagID = diag::warn_unsafe_buffer_libc_call;
2533 if (PrintfInfo & 0x8) {
2537 DiagID = diag::warn_unsafe_buffer_format_attr_call;
2540 S.Diag(
Call->getBeginLoc(), DiagID)
2541 <<
Call->getDirectCallee()
2542 <<
Call->getSourceRange();
2543 if (PrintfInfo > 0) {
2545 UnsafeArg ? UnsafeArg->getSourceRange() :
Call->getSourceRange();
2546 S.Diag(R.
getBegin(), diag::note_unsafe_buffer_printf_call)
2551 void handleUnsafeOperationInContainer(
const Stmt *Operation,
2552 bool IsRelatedToDecl,
2553 ASTContext &Ctx)
override {
2556 unsigned MsgParam = 0;
2561 Loc = CtorExpr->getLocation();
2563 S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container);
2564 if (IsRelatedToDecl) {
2565 assert(!SuggestSuggestions &&
2566 "Variables blamed for unsafe buffer usage without suggestions!");
2567 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2571 void handleUnsafeVariableGroup(
const VarDecl *Variable,
2572 const VariableGroupsManager &VarGrpMgr,
2573 FixItList &&Fixes,
const Decl *D,
2574 const FixitStrategy &VarTargetTypes)
override {
2575 assert(!SuggestSuggestions &&
2576 "Unsafe buffer usage fixits displayed without suggestions!");
2577 S.Diag(
Variable->getLocation(), diag::warn_unsafe_buffer_variable)
2580 if (!Fixes.empty()) {
2582 "Fix-its are generated only for `NamedDecl`s");
2584 bool BriefMsg =
false;
2588 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Variable, &BriefMsg);
2589 unsigned FixItStrategy = 0;
2590 switch (VarTargetTypes.
lookup(Variable)) {
2598 assert(
false &&
"We support only std::span and std::array");
2603 BriefMsg ? diag::note_unsafe_buffer_variable_fixit_together
2604 : diag::note_unsafe_buffer_variable_fixit_group);
2607 FD << listVariableGroupAsString(Variable, VarGroupForVD)
2608 << (VarGroupForVD.size() > 1) << ND;
2609 for (
const auto &F : Fixes) {
2615 if (areDebugNotesRequested())
2616 for (
const DebugNote &
Note: DebugNotesByVar[Variable])
2617 S.Diag(
Note.first, diag::note_safe_buffer_debug_mode) <<
Note.second;
2621 void handleUnsafeUniquePtrArrayAccess(
const DynTypedNode &Node,
2622 bool IsRelatedToDecl,
2623 ASTContext &Ctx)
override {
2626 Loc = Node.
get<Stmt>()->getBeginLoc();
2627 S.Diag(Loc, diag::warn_unsafe_buffer_usage_unique_ptr_array_access)
2631 bool isSafeBufferOptOut(
const SourceLocation &Loc)
const override {
2632 return S.PP.isSafeBufferOptOut(S.getSourceManager(), Loc);
2636 return S.Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container, Loc);
2639 bool ignoreUnsafeBufferInLibcCall(
const SourceLocation &Loc)
const override {
2640 return S.Diags.isIgnored(diag::warn_unsafe_buffer_libc_call, Loc);
2643 bool ignoreUnsafeBufferInStaticSizedArray(
2644 const SourceLocation &Loc)
const override {
2645 return S.Diags.isIgnored(
2646 diag::warn_unsafe_buffer_usage_in_static_sized_array, Loc);
2653 getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,
2654 StringRef WSSuffix =
"")
const override {
2655 Preprocessor &PP = S.getPreprocessor();
2656 TokenValue ClangUnsafeBufferUsageTokens[] = {
2665 StringRef MacroName;
2669 if (MacroName.empty())
2670 MacroName =
"[[clang::unsafe_buffer_usage]]";
2671 return MacroName.str() + WSSuffix.str();
2682 enableCheckFallThrough = 1;
2683 enableCheckUnreachable = 0;
2684 enableThreadSafetyAnalysis = 0;
2685 enableConsumedAnalysis = 0;
2706template <
typename... Ts>
2709 return (!D.
isIgnored(Diags, Loc) || ...);
2714 NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),
2715 MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),
2716 NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
2717 NumUninitAnalysisBlockVisits(0),
2718 MaxUninitAnalysisBlockVisitsPerFunction(0) {
2726 using namespace diag;
2732 P.enableCheckUnreachable =
2733 PolicyOverrides.enableCheckUnreachable ||
2734 areAnyEnabled(D, Loc, warn_unreachable, warn_unreachable_break,
2735 warn_unreachable_return, warn_unreachable_loop_increment);
2737 P.enableThreadSafetyAnalysis = PolicyOverrides.enableThreadSafetyAnalysis ||
2740 P.enableConsumedAnalysis = PolicyOverrides.enableConsumedAnalysis ||
2745void sema::AnalysisBasedWarnings::clearOverrides() {
2746 PolicyOverrides.enableCheckUnreachable =
false;
2747 PolicyOverrides.enableConsumedAnalysis =
false;
2748 PolicyOverrides.enableThreadSafetyAnalysis =
false;
2753 S.
Diag(D.Loc, D.PD);
2756template <
typename Iterator>
2758 std::pair<Iterator, Iterator> PUDs) {
2760 if (PUDs.first == PUDs.second)
2763 for (
auto I = PUDs.first; I != PUDs.second; ++I) {
2764 for (
const Stmt *S : I->Stmts)
2772 for (
auto I = PUDs.first; I != PUDs.second; ++I) {
2774 if (llvm::all_of(D.Stmts, [&](
const Stmt *St) {
2775 const CFGBlock *Block = AC.getBlockForRegisteredExpression(St);
2779 if (Block && Analysis)
2780 if (!Analysis->isReachable(&AC.getCFG()->getEntry(), Block))
2784 S.
Diag(D.Loc, D.PD);
2788 for (
auto I = PUDs.first; I != PUDs.second; ++I)
2789 S.
Diag(I->Loc, I->PD);
2795 VarDeclPossiblyUnreachableDiags.emplace(VD, PUD);
2800 if (!llvm::is_contained(VarDeclPossiblyUnreachableDiags, VD))
2813 auto Range = VarDeclPossiblyUnreachableDiags.equal_range(VD);
2815 llvm::make_second_range(llvm::make_range(Range.first, Range.second));
2817 S, AC, std::make_pair(SecondRange.begin(), SecondRange.end()));
2824 llvm::function_ref<void(
const Decl *)> Callback;
2825 const Module *
const TUModule;
2829 const Module *
const TUModule)
2830 : Callback(Callback), TUModule(TUModule) {
2875namespace clang::lifetimes {
2877class LifetimeSafetySemaHelperImpl :
public LifetimeSafetySemaHelper {
2880 LifetimeSafetySemaHelperImpl(Sema &S) : S(S) {}
2882 void reportUseAfterFree(
const Expr *IssueExpr,
const Expr *UseExpr,
2883 SourceLocation FreeLoc, Confidence
C)
override {
2885 C == Confidence::Definite
2886 ? diag::warn_lifetime_safety_loan_expires_permissive
2887 : diag::warn_lifetime_safety_loan_expires_strict)
2889 S.
Diag(FreeLoc, diag::note_lifetime_safety_destroyed_here);
2890 S.
Diag(UseExpr->
getExprLoc(), diag::note_lifetime_safety_used_here)
2894 void reportUseAfterReturn(
const Expr *IssueExpr,
const Expr *ReturnExpr,
2895 SourceLocation ExpiryLoc, Confidence
C)
override {
2897 C == Confidence::Definite
2898 ? diag::warn_lifetime_safety_return_stack_addr_permissive
2899 : diag::warn_lifetime_safety_return_stack_addr_strict)
2901 S.
Diag(ReturnExpr->
getExprLoc(), diag::note_lifetime_safety_returned_here)
2904 void reportDanglingField(
const Expr *IssueExpr,
2905 const FieldDecl *DanglingField,
2906 SourceLocation ExpiryLoc)
override {
2907 S.
Diag(IssueExpr->
getExprLoc(), diag::warn_lifetime_safety_dangling_field)
2910 diag::note_lifetime_safety_dangling_field_here)
2914 void suggestLifetimeboundToParmVar(SuggestionScope Scope,
2915 const ParmVarDecl *ParmToAnnotate,
2916 const Expr *EscapeExpr)
override {
2918 (Scope == SuggestionScope::CrossTU)
2919 ? diag::warn_lifetime_safety_cross_tu_param_suggestion
2920 : diag::warn_lifetime_safety_intra_tu_param_suggestion;
2926 " [[clang::lifetimebound]]");
2928 diag::note_lifetime_safety_suggestion_returned_here)
2932 void suggestLifetimeboundToImplicitThis(SuggestionScope Scope,
2933 const CXXMethodDecl *MD,
2934 const Expr *EscapeExpr)
override {
2935 unsigned DiagID = (Scope == SuggestionScope::CrossTU)
2936 ? diag::warn_lifetime_safety_cross_tu_this_suggestion
2937 : diag::warn_lifetime_safety_intra_tu_this_suggestion;
2938 SourceLocation InsertionPoint;
2942 S.
Diag(InsertionPoint, DiagID)
2945 " [[clang::lifetimebound]]");
2947 diag::note_lifetime_safety_suggestion_returned_here)
2951 void reportNoescapeViolation(
const ParmVarDecl *ParmWithNoescape,
2952 const Expr *EscapeExpr)
override {
2954 diag::warn_lifetime_safety_noescape_escapes)
2958 diag::note_lifetime_safety_suggestion_returned_here)
2962 void reportNoescapeViolation(
const ParmVarDecl *ParmWithNoescape,
2963 const FieldDecl *EscapeField)
override {
2965 diag::warn_lifetime_safety_noescape_escapes)
2969 diag::note_lifetime_safety_escapes_to_field_here)
2973 void addLifetimeBoundToImplicitThis(
const CXXMethodDecl *MD)
override {
2986 llvm::TimeTraceScope TimeProfile(
"LifetimeSafetyTUAnalysis");
2989 lifetimes::LifetimeSafetySemaHelperImpl SemaHelper(S);
2990 for (
auto *Node : llvm::post_order(&CG)) {
2992 dyn_cast_or_null<clang::FunctionDecl>(Node->getDecl());
3006 runLifetimeSafetyAnalysis(AC, &SemaHelper, LSStats, S.
CollectStats);
3024 bool UnsafeBufferUsageCanEmitSuggestions = S.getLangOpts().CPlusPlus20;
3025 bool UnsafeBufferUsageShouldEmitSuggestions =
3026 UnsafeBufferUsageCanEmitSuggestions &&
3027 DiagOpts.ShowSafeBufferUsageSuggestions;
3028 bool UnsafeBufferUsageShouldSuggestSuggestions =
3029 UnsafeBufferUsageCanEmitSuggestions &&
3030 !DiagOpts.ShowSafeBufferUsageSuggestions;
3031 UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions);
3034 auto CallAnalyzers = [&](
const Decl *Node) ->
void {
3035 if (Node->hasAttr<UnsafeBufferUsageAttr>())
3039 if (!Diags.
isIgnored(diag::warn_unsafe_buffer_operation,
3040 Node->getBeginLoc()) ||
3041 !Diags.
isIgnored(diag::warn_unsafe_buffer_variable,
3042 Node->getBeginLoc()) ||
3043 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
3044 Node->getBeginLoc()) ||
3045 !Diags.
isIgnored(diag::warn_unsafe_buffer_libc_call,
3046 Node->getBeginLoc())) {
3048 UnsafeBufferUsageShouldEmitSuggestions);
3057 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
3060 S.getLangOpts().CPlusPlus )) {
3062 .TraverseTranslationUnitDecl(TU);
3065 if (S.getLangOpts().EnableLifetimeSafety && S.getLangOpts().CPlusPlus &&
3066 S.getLangOpts().EnableLifetimeSafetyTUAnalysis)
3092 if (S.hasUncompilableErrorOccurred()) {
3115 bool IsLifetimeSafetyDiagnosticEnabled =
3116 !Diags.
isIgnored(diag::warn_lifetime_safety_loan_expires_permissive,
3118 !Diags.
isIgnored(diag::warn_lifetime_safety_loan_expires_strict,
3120 !Diags.
isIgnored(diag::warn_lifetime_safety_return_stack_addr_permissive,
3122 !Diags.
isIgnored(diag::warn_lifetime_safety_return_stack_addr_strict,
3124 !Diags.
isIgnored(diag::warn_lifetime_safety_noescape_escapes,
3126 bool EnableLifetimeSafetyAnalysis =
3127 S.getLangOpts().EnableLifetimeSafety &&
3128 !S.getLangOpts().EnableLifetimeSafetyTUAnalysis &&
3129 IsLifetimeSafetyDiagnosticEnabled;
3137 if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||
3138 P.enableConsumedAnalysis || EnableLifetimeSafetyAnalysis) {
3151 if (EnableLifetimeSafetyAnalysis)
3155 std::optional<LogicalErrorHandler> LEH;
3156 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->
getBeginLoc())) {
3166 if (P.enableCheckFallThrough) {
3167 const CheckFallThroughDiagnostics &CD =
3172 ? CheckFallThroughDiagnostics::MakeForLambda()
3174 ? CheckFallThroughDiagnostics::MakeForCoroutine(D)
3175 : CheckFallThroughDiagnostics::MakeForFunction(S, D)));
3180 if (P.enableCheckUnreachable) {
3193 if (P.enableThreadSafetyAnalysis) {
3196 threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
3198 Reporter.setIssueBetaWarnings(
true);
3200 Reporter.setVerbose(
true);
3203 &S.ThreadSafetyDeclCache);
3204 Reporter.emitDiagnostics();
3208 if (P.enableConsumedAnalysis) {
3209 consumed::ConsumedWarningsHandler WarningHandler(S);
3220 UninitValsDiagReporter reporter(S);
3227 ++NumUninitAnalysisFunctions;
3230 MaxUninitAnalysisVariablesPerFunction =
3231 std::max(MaxUninitAnalysisVariablesPerFunction,
3233 MaxUninitAnalysisBlockVisitsPerFunction =
3234 std::max(MaxUninitAnalysisBlockVisitsPerFunction,
3242 if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {
3244 lifetimes::LifetimeSafetySemaHelperImpl LifetimeSafetySemaHelper(S);
3246 LSStats, S.CollectStats);
3250 if (S.getLangOpts().ObjC && !S.getLangOpts().CPlusPlus &&
3251 shouldAnalyzeCalledOnceParameters(Diags, D->
getBeginLoc())) {
3253 CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);
3256 shouldAnalyzeCalledOnceConventions(Diags, D->
getBeginLoc()));
3260 bool FallThroughDiagFull =
3262 bool FallThroughDiagPerFunction = !Diags.
isIgnored(
3263 diag::warn_unannotated_fallthrough_per_function, D->
getBeginLoc());
3264 if (FallThroughDiagFull || FallThroughDiagPerFunction ||
3269 if (S.getLangOpts().ObjCWeak &&
3275 if (!Diags.
isIgnored(diag::warn_infinite_recursive_function,
3277 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
3284 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
3290 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->
getBeginLoc())) {
3299 ++NumFunctionsAnalyzed;
3303 NumCFGBlocks += cfg->getNumBlockIDs();
3304 MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
3305 cfg->getNumBlockIDs());
3307 ++NumFunctionsWithBadCFGs;
3313 llvm::errs() <<
"\n*** Analysis Based Warnings Stats:\n";
3315 unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
3316 unsigned AvgCFGBlocksPerFunction =
3317 !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
3318 llvm::errs() << NumFunctionsAnalyzed <<
" functions analyzed ("
3319 << NumFunctionsWithBadCFGs <<
" w/o CFGs).\n"
3320 <<
" " << NumCFGBlocks <<
" CFG blocks built.\n"
3321 <<
" " << AvgCFGBlocksPerFunction
3322 <<
" average CFG blocks per function.\n"
3323 <<
" " << MaxCFGBlocksPerFunction
3324 <<
" max CFG blocks per function.\n";
3326 unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
3327 : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
3328 unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
3329 : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
3330 llvm::errs() << NumUninitAnalysisFunctions
3331 <<
" functions analyzed for uninitialiazed variables\n"
3332 <<
" " << NumUninitAnalysisVariables <<
" variables analyzed.\n"
3333 <<
" " << AvgUninitVariablesPerFunction
3334 <<
" average variables per function.\n"
3335 <<
" " << MaxUninitAnalysisVariablesPerFunction
3336 <<
" max variables per function.\n"
3337 <<
" " << NumUninitAnalysisBlockVisits <<
" block visits.\n"
3338 <<
" " << AvgUninitBlockVisitsPerFunction
3339 <<
" average block visits per function.\n"
3340 <<
" " << MaxUninitAnalysisBlockVisitsPerFunction
3341 <<
" 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...
DeclarationNameInfo getNameInfo() const
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.
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)
Computes the source location just past the end of the token at this source location.
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
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
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)
void addLifetimeBoundToImplicitThis(CXXMethodDecl *MD)
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.
SourceLocation getEndLoc() const
Get the end source location.
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
QualType getType() const
Return the type wrapped by this type source info.
bool isBlockPointerType() const
bool isPointerType() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
const T * castAs() const
Member-template castAs<specific type>.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
TagDecl * getAsTagDecl() const
Retrieves the TagDecl that this type refers to, either because the type is a TagType or because it is...
const T * getAs() const
Member-template getAs<specific type>'.
Expr * getSubExpr() const
A use of a variable, which might be uninitialized.
const Expr * getUser() const
Get the expression containing the uninitialized use.
SmallVectorImpl< Branch >::const_iterator branch_iterator
branch_iterator branch_end() const
bool isConstPtrUse() const
bool isConstRefOrPtrUse() const
bool isConstRefUse() const
branch_iterator branch_begin() const
Branches which inevitably result in the variable being used uninitialized.
@ Always
The use is always uninitialized.
@ AfterDecl
The use is uninitialized the first time it is reached after we reach the variable's declaration.
@ Maybe
The use might be uninitialized.
@ AfterCall
The use is uninitialized the first time it is reached after the function is called.
@ Sometimes
The use is uninitialized whenever a certain branch is taken.
Kind getKind() const
Get the kind of uninitialized use.
The interface that lets the caller handle unsafe buffer usage analysis results by overriding this cla...
Represents a variable declaration or definition.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
VarDecl * getDefinition(ASTContext &)
Get the real (not just tentative) definition for this declaration.
const Expr * getInit() const
virtual VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm=nullptr) const =0
Returns the set of variables (including Var) that need to be fixed together in one step.
A class that handles the analysis of uniqueness violations.
void issueWarningsForRegisteredVarDecl(VarDecl *VD)
void IssueWarnings(Policy P, FunctionScopeInfo *fscope, const Decl *D, QualType BlockType)
void registerVarDeclWarning(VarDecl *VD, PossiblyUnreachableDiag PUD)
AnalysisBasedWarnings(Sema &s)
Policy getPolicyInEffectAt(SourceLocation Loc)
Represents a simple identification of a weak object.
Retains information about a function, method, or block that is currently being parsed.
bool HasFallthroughStmt
Whether there is a fallthrough statement in this function.
SmallVector< WeakUseTy, 4 > WeakUseVector
Used to collect uses of a particular weak object in a function body.
SmallVector< PossiblyUnreachableDiag, 4 > PossiblyUnreachableDiags
A list of PartialDiagnostics created but delayed within the current function scope.
llvm::SmallDenseMap< WeakObjectProfileTy, WeakUseVector, 8, WeakObjectProfileTy::DenseMapInfo > WeakObjectUseMap
Used to collect all uses of weak objects in a function body.
const WeakObjectUseMap & getWeakObjectUses() const
InterProceduralData aims to be a storage of whatever data should be passed between analyses of differ...
CalledOnceInterProceduralData CalledOnceData
std::list< DelayedDiag > DiagList
std::pair< PartialDiagnosticAt, OptionalNotes > DelayedDiag
SmallVector< PartialDiagnosticAt, 1 > OptionalNotes
uint32_t Variable
Boolean variables are represented as positive integers.
bool LE(InterpState &S, CodePtr OpPC)
void printStats(const LifetimeSafetyStats &Stats)
Utility function to print missing origin stats.
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)
SourceRange getSourceRange() const LLVM_READONLY
getSourceRange - The range of the declaration name.
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.