49#include "llvm/ADT/ArrayRef.h"
50#include "llvm/ADT/BitVector.h"
51#include "llvm/ADT/DenseMap.h"
52#include "llvm/ADT/MapVector.h"
53#include "llvm/ADT/PostOrderIterator.h"
54#include "llvm/ADT/STLFunctionalExtras.h"
55#include "llvm/ADT/SmallVector.h"
56#include "llvm/ADT/StringRef.h"
57#include "llvm/Support/Debug.h"
58#include "llvm/Support/TimeProfiler.h"
73 SourceRange PreviousSilenceableCondVal;
76 UnreachableCodeHandler(Sema &
s) : S(
s) {}
79 SourceRange SilenceableCondVal, SourceRange R1,
80 SourceRange R2,
bool HasFallThroughAttr)
override {
84 if (HasFallThroughAttr &&
85 !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr,
91 if (PreviousSilenceableCondVal.isValid() &&
93 PreviousSilenceableCondVal == SilenceableCondVal)
95 PreviousSilenceableCondVal = SilenceableCondVal;
97 unsigned diag = diag::warn_unreachable;
100 diag = diag::warn_unreachable_break;
103 diag = diag::warn_unreachable_return;
106 diag = diag::warn_unreachable_loop_increment;
112 S.Diag(L, diag) << R1 << R2;
115 if (
Open.isValid()) {
116 SourceLocation Close = SilenceableCondVal.
getEnd();
117 Close = S.getLocForEndOfToken(Close);
119 S.Diag(
Open, diag::note_unreachable_silence)
140 UnreachableCodeHandler UC(S);
150 LogicalErrorHandler(Sema &S) : S(S) {}
152 static bool HasMacroID(
const Expr *E) {
157 for (
const Stmt *SubStmt : E->
children())
158 if (
const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt))
159 if (HasMacroID(SubExpr))
165 void logicAlwaysTrue(
const BinaryOperator *B,
bool isAlwaysTrue)
override {
169 unsigned DiagID = isAlwaysTrue
170 ? diag::warn_tautological_negation_or_compare
171 : diag::warn_tautological_negation_and_compare;
176 void compareAlwaysTrue(
const BinaryOperator *B,
177 bool isAlwaysTrueOrFalse)
override {
182 S.Diag(B->
getExprLoc(), diag::warn_tautological_overlap_comparison)
183 << DiagRange << isAlwaysTrueOrFalse;
186 void compareBitwiseEquality(
const BinaryOperator *B,
187 bool isAlwaysTrue)
override {
192 S.Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_always)
193 << DiagRange << isAlwaysTrue;
196 void compareBitwiseOr(
const BinaryOperator *B)
override {
201 S.Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;
204 static bool hasActiveDiagnostics(DiagnosticsEngine &Diags,
205 SourceLocation Loc) {
206 return !Diags.
isIgnored(diag::warn_tautological_overlap_comparison, Loc) ||
207 !Diags.
isIgnored(diag::warn_comparison_bitwise_or, Loc) ||
208 !Diags.
isIgnored(diag::warn_tautological_negation_and_compare, Loc);
222 for (
const auto &B :
Block) {
236 if (isa_and_nonnull<TemplateSpecializationType>(NNS.getAsType()))
252 bool foundRecursion =
false;
257 WorkList.push_back(&cfg->
getEntry());
259 while (!WorkList.empty()) {
262 for (
auto I =
Block->succ_begin(), E =
Block->succ_end(); I != E; ++I) {
264 if (!Visited.insert(SuccBlock).second)
268 if (ExitID == SuccBlock->getBlockID())
273 foundRecursion =
true;
277 WorkList.push_back(SuccBlock);
281 return foundRecursion;
317 Stack.push_back(&ThrowBlock);
320 while (!Stack.empty()) {
321 CFGBlock &UnwindBlock = *Stack.pop_back_val();
323 for (
auto &Succ : UnwindBlock.
succs()) {
324 if (!Succ.isReachable() || Queued[Succ->getBlockID()])
331 dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
332 QualType Caught = Catch->getCaughtType();
339 Stack.push_back(Succ);
340 Queued[Succ->getBlockID()] =
true;
354 if (!Reachable[B->getBlockID()])
357 std::optional<CFGStmt> S = E.getAs<
CFGStmt>();
360 if (
auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))
370 S.
Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
376 getAs<FunctionProtoType>())
401 if (FPT->isNothrow() || FD->
hasAttr<NoThrowAttr>())
410 if (
auto *FD = dyn_cast<FunctionDecl>(DRef->getDecl()))
411 return FD->isNoReturn();
430struct TransferFunctions :
public StmtVisitor<TransferFunctions> {
432 std::optional<bool> AllValuesAreNoReturn;
434 TransferFunctions(
const VarDecl *VD) : Var(VD) {}
436 void reset() { AllValuesAreNoReturn = std::nullopt; }
438 void VisitDeclStmt(DeclStmt *DS) {
439 for (
auto *DI : DS->
decls())
440 if (
auto *VD = dyn_cast<VarDecl>(DI))
441 if (VarDecl *Def = VD->getDefinition())
446 void VisitUnaryOperator(UnaryOperator *UO) {
450 if (DRef->getDecl() == Var)
451 AllValuesAreNoReturn =
false;
455 void VisitBinaryOperator(BinaryOperator *BO) {
458 if (DRef->getDecl() == Var)
462 void VisitCallExpr(CallExpr *CE) {
465 const Expr *Arg = *I;
468 if (
auto VD = dyn_cast<VarDecl>(DRef->getDecl()))
469 if (VD->getDefinition() == Var)
470 AllValuesAreNoReturn =
false;
496 using MapTy = llvm::DenseMap<const CFGBlock *, std::optional<bool>>;
497 using ValueTy = MapTy::value_type;
499 BlocksToCheck[&VarBlk] = std::nullopt;
500 const auto BlockSatisfiesCondition = [](ValueTy Item) {
501 return Item.getSecond().value_or(
false);
504 TransferFunctions TF(VD);
506 llvm::DenseSet<const CFGBlock *> Visited;
509 if (Visited.contains(B))
515 if (std::optional<CFGStmt> cs = ri->getAs<
CFGStmt>()) {
516 const Stmt *S = cs->getStmt();
518 TF.Visit(
const_cast<Stmt *
>(S));
519 if (TF.AllValuesAreNoReturn) {
520 if (!TF.AllValuesAreNoReturn.value())
522 BlocksToCheck[B] =
true;
529 if (llvm::all_of(BlocksToCheck, BlockSatisfiesCondition))
534 if (!BlocksToCheck[B]) {
536 BlocksToCheck.erase(B);
537 for (
const auto &PredBlk : B->preds())
538 if (!BlocksToCheck.contains(PredBlk))
539 BlocksToCheck[PredBlk] = std::nullopt;
582 for (
const auto *B : *cfg) {
583 if (!live[B->getBlockID()]) {
584 if (B->preds().empty()) {
585 const Stmt *Term = B->getTerminatorStmt();
586 if (isa_and_nonnull<CXXTryStmt>(Term))
598 bool HasLiveReturn =
false;
599 bool HasFakeEdge =
false;
600 bool HasPlainEdge =
false;
601 bool HasAbnormalEdge =
false;
619 HasAbnormalEdge =
true;
628 for ( ; ri != re ; ++ri)
636 HasAbnormalEdge =
true;
647 HasLiveReturn =
true;
661 HasLiveReturn =
true;
665 HasAbnormalEdge =
true;
669 HasAbnormalEdge =
true;
672 if (
auto *
Call = dyn_cast<CallExpr>(S)) {
673 const Expr *Callee =
Call->getCallee();
674 if (Callee->getType()->isPointerType())
676 dyn_cast<DeclRefExpr>(Callee->IgnoreParenImpCasts()))
677 if (
auto *VD = dyn_cast<VarDecl>(DeclRef->getDecl()))
679 HasAbnormalEdge =
true;
691 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
701struct CheckFallThroughDiagnostics {
702 unsigned diag_FallThrough_HasNoReturn = 0;
703 unsigned diag_FallThrough_ReturnsNonVoid = 0;
704 unsigned diag_NeverFallThroughOrReturn = 0;
706 SourceLocation FuncLoc;
708 static CheckFallThroughDiagnostics MakeForFunction(Sema &S,
710 CheckFallThroughDiagnostics D;
711 D.FuncLoc =
Func->getLocation();
712 D.diag_FallThrough_HasNoReturn = diag::warn_noreturn_has_return_expr;
713 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
717 bool isVirtualMethod =
false;
718 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(
Func))
719 isVirtualMethod =
Method->isVirtual();
723 if (
const FunctionDecl *
Function = dyn_cast<FunctionDecl>(
Func)) {
727 D.diag_FallThrough_ReturnsNonVoid = diag::ext_main_no_return;
732 D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function;
734 D.FunKind = diag::FalloffFunctionKind::Function;
738 static CheckFallThroughDiagnostics MakeForCoroutine(
const Decl *
Func) {
739 CheckFallThroughDiagnostics D;
740 D.FuncLoc =
Func->getLocation();
741 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
742 D.FunKind = diag::FalloffFunctionKind::Coroutine;
746 static CheckFallThroughDiagnostics MakeForBlock() {
747 CheckFallThroughDiagnostics D;
748 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;
749 D.diag_FallThrough_ReturnsNonVoid = diag::err_falloff_nonvoid;
750 D.FunKind = diag::FalloffFunctionKind::Block;
754 static CheckFallThroughDiagnostics MakeForLambda() {
755 CheckFallThroughDiagnostics D;
756 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;
757 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
758 D.FunKind = diag::FalloffFunctionKind::Lambda;
762 bool checkDiagnostics(DiagnosticsEngine &D,
bool ReturnsVoid,
763 bool HasNoReturn)
const {
764 if (FunKind == diag::FalloffFunctionKind::Function) {
765 return (ReturnsVoid ||
766 D.
isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&
768 D.
isIgnored(diag::warn_noreturn_has_return_expr, FuncLoc)) &&
770 D.
isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));
772 if (FunKind == diag::FalloffFunctionKind::Coroutine) {
773 return (ReturnsVoid ||
774 D.
isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&
778 return ReturnsVoid && !HasNoReturn;
790 const CheckFallThroughDiagnostics &CD,
793 bool ReturnsVoid =
false;
794 bool HasNoReturn =
false;
796 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
797 if (
const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
798 ReturnsVoid = CBody->getFallthroughHandler() !=
nullptr;
800 ReturnsVoid = FD->getReturnType()->isVoidType();
801 HasNoReturn = FD->isNoReturn() || FD->hasAttr<InferredNoReturnAttr>();
803 else if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
804 ReturnsVoid = MD->getReturnType()->isVoidType();
805 HasNoReturn = MD->hasAttr<NoReturnAttr>();
810 if (FT->getReturnType()->isVoidType())
812 if (FT->getNoReturnAttr())
820 if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
836 if (CD.diag_FallThrough_HasNoReturn)
837 S.
Diag(RBrace, CD.diag_FallThrough_HasNoReturn) << CD.FunKind;
838 }
else if (!ReturnsVoid && CD.diag_FallThrough_ReturnsNonVoid) {
842 if (
const auto *CS = dyn_cast<CompoundStmt>(Body);
843 CS && !CS->body_empty()) {
844 const Stmt *LastStmt = CS->body_back();
846 if (
const auto *EWC = dyn_cast<ExprWithCleanups>(LastStmt)) {
847 LastStmt = EWC->getSubExpr();
849 if (
const auto *CE = dyn_cast<CallExpr>(LastStmt)) {
851 Callee && Callee->hasAttr<InferredNoReturnAttr>()) {
862 S.
Diag(RBrace, CD.diag_FallThrough_ReturnsNonVoid)
863 << CD.FunKind << NotInAllControlPaths;
867 if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
868 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
869 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
870 }
else if (
const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
871 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
873 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
892 const DeclRefExpr *Needle;
895 typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited;
897 ContainsReference(ASTContext &Context,
const DeclRefExpr *Needle)
898 : Inherited(Context), FoundReference(
false), Needle(Needle) {}
900 void VisitExpr(
const Expr *E) {
905 Inherited::VisitExpr(E);
908 void VisitDeclRefExpr(
const DeclRefExpr *E) {
910 FoundReference =
true;
915 bool doesContainReference()
const {
return FoundReference; }
923 S.
Diag(VD->
getLocation(), diag::note_block_var_fixit_add_initialization)
944 S.
Diag(Loc, diag::note_var_fixit_add_initialization) << VD->
getDeclName()
952 const Stmt *Else,
bool CondVal,
976 bool IsCapturedByBlock) {
977 bool Diagnosed =
false;
1009 const Stmt *Term = I->Terminator;
1019 int RemoveDiagKind = -1;
1020 const char *FixitStr =
1021 S.
getLangOpts().CPlusPlus ? (I->Output ?
"true" :
"false")
1022 : (I->Output ?
"1" :
"0");
1025 switch (Term ? Term->
getStmtClass() : Stmt::DeclStmtClass) {
1032 case Stmt::IfStmtClass: {
1039 I->Output, Fixit1, Fixit2);
1042 case Stmt::ConditionalOperatorClass: {
1049 I->Output, Fixit1, Fixit2);
1052 case Stmt::BinaryOperatorClass: {
1060 if ((BO->
getOpcode() == BO_LAnd && I->Output) ||
1061 (BO->
getOpcode() == BO_LOr && !I->Output))
1072 case Stmt::WhileStmtClass:
1079 case Stmt::ForStmtClass:
1089 case Stmt::CXXForRangeStmtClass:
1090 if (I->Output == 1) {
1102 case Stmt::DoStmtClass:
1105 Range =
cast<DoStmt>(Term)->getCond()->getSourceRange();
1111 case Stmt::CaseStmtClass:
1116 case Stmt::DefaultStmtClass:
1123 S.
Diag(Range.getBegin(), diag::warn_sometimes_uninit_var)
1124 << VD->
getDeclName() << IsCapturedByBlock << DiagKind
1125 << Str << I->Output << Range;
1128 if (RemoveDiagKind != -1)
1130 << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
1164 bool alwaysReportSelfInit =
false) {
1178 if (!alwaysReportSelfInit && DRE ==
Initializer->IgnoreParenImpCasts())
1181 ContainsReference CR(S.
Context, DRE);
1183 if (CR.doesContainReference()) {
1184 S.
Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
1195 diag::warn_uninit_byref_blockvar_captured_by_block)
1215 FallthroughMapper(Sema &S) : FoundSwitchStatements(
false), S(S) {
1216 ShouldWalkTypesOfTypeLocs =
false;
1219 bool foundSwitchStatements()
const {
return FoundSwitchStatements; }
1221 void markFallthroughVisited(
const AttributedStmt *Stmt) {
1222 bool Found = FallthroughStmts.erase(Stmt);
1227 typedef llvm::SmallPtrSet<const AttributedStmt *, 8> AttrStmts;
1229 const AttrStmts &getFallthroughStmts()
const {
return FallthroughStmts; }
1231 void fillReachableBlocks(CFG *Cfg) {
1232 assert(ReachableBlocks.empty() &&
"ReachableBlocks already filled");
1233 std::deque<const CFGBlock *> BlockQueue;
1235 ReachableBlocks.insert(&Cfg->
getEntry());
1236 BlockQueue.push_back(&Cfg->
getEntry());
1241 for (
const auto *B : *Cfg) {
1242 const Stmt *L = B->getLabel();
1243 if (isa_and_nonnull<SwitchCase>(L) && ReachableBlocks.insert(B).second)
1244 BlockQueue.push_back(B);
1247 while (!BlockQueue.empty()) {
1248 const CFGBlock *P = BlockQueue.front();
1249 BlockQueue.pop_front();
1250 for (
const CFGBlock *B : P->
succs()) {
1251 if (B && ReachableBlocks.insert(B).second)
1252 BlockQueue.push_back(B);
1257 bool checkFallThroughIntoBlock(
const CFGBlock &B,
int &AnnotatedCnt,
1258 bool IsTemplateInstantiation) {
1259 assert(!ReachableBlocks.empty() &&
"ReachableBlocks empty");
1261 int UnannotatedCnt = 0;
1265 while (!BlockQueue.empty()) {
1266 const CFGBlock *P = BlockQueue.
front();
1267 BlockQueue.pop_front();
1272 if (isa_and_nonnull<SwitchStmt>(Term))
1275 const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->
getLabel());
1279 const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->
getLabel());
1283 if (!ReachableBlocks.count(P)) {
1284 for (
const CFGElement &Elem : llvm::reverse(*P)) {
1285 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) {
1286 if (
const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
1290 if (!IsTemplateInstantiation)
1291 S.Diag(AS->getBeginLoc(),
1292 diag::warn_unreachable_fallthrough_attr);
1293 markFallthroughVisited(AS);
1312 if (
const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {
1313 markFallthroughVisited(AS);
1321 std::back_inserter(BlockQueue));
1327 return !!UnannotatedCnt;
1330 bool VisitAttributedStmt(AttributedStmt *S)
override {
1331 if (asFallThroughAttr(S))
1332 FallthroughStmts.insert(S);
1336 bool VisitSwitchStmt(SwitchStmt *S)
override {
1337 FoundSwitchStatements =
true;
1343 bool TraverseDecl(Decl *D)
override {
return true; }
1346 bool TraverseLambdaExpr(
LambdaExpr *LE)
override {
1348 for (
const auto C : zip(
LE->captures(),
LE->capture_inits()))
1349 TraverseLambdaCapture(LE, &std::get<0>(
C), std::get<1>(
C));
1355 static const AttributedStmt *asFallThroughAttr(
const Stmt *S) {
1356 if (
const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
1363 static const Stmt *
getLastStmt(
const CFGBlock &B) {
1366 for (
const CFGElement &Elem : llvm::reverse(B))
1367 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
1368 return CS->getStmt();
1372 if (
const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.
getLabel()))
1379 bool FoundSwitchStatements;
1380 AttrStmts FallthroughStmts;
1382 llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
1389 tok::l_square, tok::l_square,
1391 tok::r_square, tok::r_square
1397 tok::r_square, tok::r_square
1402 StringRef MacroName;
1403 if (PreferClangAttr)
1405 if (MacroName.empty())
1407 if (MacroName.empty() && !PreferClangAttr)
1409 if (MacroName.empty()) {
1410 if (!PreferClangAttr)
1411 MacroName =
"[[fallthrough]]";
1413 MacroName =
"[[clang::fallthrough]]";
1415 MacroName =
"__attribute__((fallthrough))";
1422 FallthroughMapper FM(S);
1423 FM.TraverseStmt(AC.
getBody());
1425 if (!FM.foundSwitchStatements())
1428 if (PerFunction && FM.getFallthroughStmts().empty())
1436 FM.fillReachableBlocks(Cfg);
1438 for (
const CFGBlock *B : llvm::reverse(*Cfg)) {
1441 if (!isa_and_nonnull<SwitchCase>(Label))
1446 bool IsTemplateInstantiation =
false;
1448 IsTemplateInstantiation = Function->isTemplateInstantiation();
1449 if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,
1450 IsTemplateInstantiation))
1454 PerFunction ? diag::warn_unannotated_fallthrough_per_function
1455 : diag::warn_unannotated_fallthrough);
1457 if (!AnnotatedCnt) {
1468 if (!(B->
empty() && isa_and_nonnull<BreakStmt>(Term))) {
1472 TextToInsert +=
"; ";
1473 S.
Diag(L, diag::note_insert_fallthrough_fixit)
1474 << AnnotationSpelling
1477 S.
Diag(L, diag::note_insert_break_fixit)
1482 for (
const auto *F : FM.getFallthroughStmts())
1483 S.
Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement);
1492 case Stmt::ForStmtClass:
1493 case Stmt::WhileStmtClass:
1494 case Stmt::CXXForRangeStmtClass:
1495 case Stmt::ObjCForCollectionStmtClass:
1497 case Stmt::DoStmtClass: {
1501 return Result.
Val.
getInt().getBoolValue();
1518 typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
1527 for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end();
1529 const WeakUseVector &Uses = I->second;
1532 WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
1533 for ( ; UI != UE; ++UI) {
1546 if (UI == Uses.begin()) {
1547 WeakUseVector::const_iterator UI2 = UI;
1548 for (++UI2; UI2 != UE; ++UI2)
1549 if (UI2->isUnsafe())
1553 if (!
isInLoop(Ctx, PM, UI->getUseExpr()))
1556 const WeakObjectProfileTy &Profile = I->first;
1557 if (!Profile.isExactProfile())
1562 Base = Profile.getProperty();
1563 assert(
Base &&
"A profile always has a base or property.");
1565 if (
const VarDecl *BaseVar = dyn_cast<VarDecl>(
Base))
1571 UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
1574 if (UsesByStmt.empty())
1579 llvm::sort(UsesByStmt,
1580 [&
SM](
const StmtUsesPair &LHS,
const StmtUsesPair &RHS) {
1581 return SM.isBeforeInTranslationUnit(LHS.first->getBeginLoc(),
1582 RHS.first->getBeginLoc());
1598 FunctionKind =
Block;
1600 FunctionKind = Lambda;
1602 FunctionKind = Method;
1604 FunctionKind = Function;
1607 for (
const auto &P : UsesByStmt) {
1608 const Stmt *FirstRead = P.first;
1609 const WeakObjectProfileTy &Key = P.second->first;
1610 const WeakUseVector &Uses = P.second->second;
1618 if (Key.isExactProfile())
1619 DiagKind = diag::warn_arc_repeated_use_of_weak;
1621 DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
1633 const NamedDecl *KeyProp = Key.getProperty();
1635 ObjectKind = Variable;
1637 ObjectKind = Property;
1639 ObjectKind = ImplicitProperty;
1643 llvm_unreachable(
"Unexpected weak object kind!");
1648 if (Prop->hasAttr<IBOutletAttr>())
1653 <<
int(ObjectKind) << KeyProp <<
int(FunctionKind)
1657 for (
const auto &Use : Uses) {
1658 if (Use.getUseExpr() == FirstRead)
1660 S.
Diag(Use.getUseExpr()->getBeginLoc(),
1661 diag::note_arc_weak_also_accessed_here)
1662 << Use.getUseExpr()->getSourceRange();
1670typedef std::pair<PartialDiagnosticAt, OptionalNotes>
DelayedDiag;
1671typedef std::list<DelayedDiag>
DiagList;
1673struct SortDiagBySourceLocation {
1675 SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {}
1677 bool operator()(
const DelayedDiag &left,
const DelayedDiag &right) {
1680 return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
1689 typedef SmallVector<UninitUse, 2> UsesVec;
1690 typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
1694 typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
1698 UninitValsDiagReporter(Sema &S) : S(S) {}
1701 MappedType &getUses(
const VarDecl *vd) {
1702 MappedType &
V = uses[vd];
1703 if (!
V.getPointer())
1704 V.setPointer(
new UsesVec());
1708 void handleUseOfUninitVariable(
const VarDecl *vd,
1709 const UninitUse &use)
override {
1710 getUses(vd).getPointer()->push_back(use);
1713 void handleSelfInit(
const VarDecl *vd)
override { getUses(vd).setInt(
true); }
1716 for (
const auto &P : uses) {
1717 const VarDecl *vd = P.first;
1718 const MappedType &
V = P.second;
1720 UsesVec *vec =
V.getPointer();
1721 bool hasSelfInit =
V.getInt();
1723 diagnoseUnitializedVar(vd, hasSelfInit, vec);
1733 static bool hasAlwaysUninitializedUse(
const UsesVec* vec) {
1734 return llvm::any_of(*vec, [](
const UninitUse &U) {
1744 void diagnoseUnitializedVar(
const VarDecl *vd,
bool hasSelfInit,
1749 if (hasSelfInit && hasAlwaysUninitializedUse(vec)) {
1760 llvm::sort(*vec, [](
const UninitUse &a,
const UninitUse &
b) {
1764 return b.isConstRefOrPtrUse();
1771 for (
const auto &U : *vec) {
1780 UninitUse Use = hasSelfInit ? UninitUse(U.
getUser(),
false) : U;
1789class CalledOnceInterProceduralData {
1792 void addDelayedWarning(
const BlockDecl *
Block,
1794 DelayedBlockWarnings[
Block].emplace_back(std::move(
Warning));
1797 void flushWarnings(
const BlockDecl *
Block, Sema &S) {
1799 S.
Diag(Delayed.first, Delayed.second);
1801 discardWarnings(
Block);
1804 void discardWarnings(
const BlockDecl *
Block) {
1805 DelayedBlockWarnings.erase(
Block);
1809 using DelayedDiagnostics = SmallVector<PartialDiagnosticAt, 2>;
1810 llvm::DenseMap<const BlockDecl *, DelayedDiagnostics> DelayedBlockWarnings;
1815 CalledOnceCheckReporter(Sema &S, CalledOnceInterProceduralData &Data)
1816 : S(S), Data(Data) {}
1817 void handleDoubleCall(
const ParmVarDecl *
Parameter,
const Expr *
Call,
1818 const Expr *PrevCall,
bool IsCompletionHandler,
1819 bool Poised)
override {
1820 auto DiagToReport = IsCompletionHandler
1821 ? diag::warn_completion_handler_called_twice
1822 : diag::warn_called_once_gets_called_twice;
1824 S.Diag(PrevCall->
getBeginLoc(), diag::note_called_once_gets_called_twice)
1828 void handleNeverCalled(
const ParmVarDecl *
Parameter,
1829 bool IsCompletionHandler)
override {
1830 auto DiagToReport = IsCompletionHandler
1831 ? diag::warn_completion_handler_never_called
1832 : diag::warn_called_once_never_called;
1833 S.Diag(
Parameter->getBeginLoc(), DiagToReport)
1839 bool IsCalledDirectly,
1840 bool IsCompletionHandler)
override {
1841 auto DiagToReport = IsCompletionHandler
1842 ? diag::warn_completion_handler_never_called_when
1843 : diag::warn_called_once_never_called_when;
1847 << (
unsigned)Reason);
1857 void handleCapturedNeverCalled(
const ParmVarDecl *
Parameter,
1859 bool IsCompletionHandler)
override {
1860 auto DiagToReport = IsCompletionHandler
1861 ? diag::warn_completion_handler_never_called
1862 : diag::warn_called_once_never_called;
1868 handleBlockThatIsGuaranteedToBeCalledOnce(
const BlockDecl *
Block)
override {
1869 Data.flushWarnings(
Block, S);
1872 void handleBlockWithNoGuarantees(
const BlockDecl *
Block)
override {
1873 Data.discardWarnings(
Block);
1878 CalledOnceInterProceduralData &Data;
1881constexpr unsigned CalledOnceWarnings[] = {
1882 diag::warn_called_once_never_called,
1883 diag::warn_called_once_never_called_when,
1884 diag::warn_called_once_gets_called_twice};
1886constexpr unsigned CompletionHandlerWarnings[]{
1887 diag::warn_completion_handler_never_called,
1888 diag::warn_completion_handler_never_called_when,
1889 diag::warn_completion_handler_called_twice};
1894 return llvm::any_of(DiagIDs, [&Diags, At](
unsigned DiagID) {
1901 return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);
1906 return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||
1907 shouldAnalyzeCalledOnceConventions(Diags, At);
1917class ThreadSafetyReporter :
public clang::threadSafety::ThreadSafetyHandler {
1920 SourceLocation FunLocation, FunEndLocation;
1922 const FunctionDecl *CurrentFunction;
1926 if (Verbose && CurrentFunction) {
1928 S.PDiag(diag::note_thread_warning_in_fun)
1929 << CurrentFunction);
1937 if (Verbose && CurrentFunction) {
1939 S.PDiag(diag::note_thread_warning_in_fun)
1940 << CurrentFunction);
1941 ONS.push_back(std::move(FNote));
1949 ONS.push_back(Note1);
1950 ONS.push_back(Note2);
1951 if (Verbose && CurrentFunction) {
1953 S.PDiag(diag::note_thread_warning_in_fun)
1954 << CurrentFunction);
1955 ONS.push_back(std::move(FNote));
1960 OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) {
1963 LocLocked, S.PDiag(diag::note_locked_here) << Kind))
1967 OptionalNotes makeUnlockedHereNote(SourceLocation LocUnlocked,
1971 LocUnlocked, S.PDiag(diag::note_unlocked_here) << Kind))
1975 OptionalNotes makeManagedMismatchNoteForParam(SourceLocation DeclLoc) {
1979 S.PDiag(diag::note_managed_mismatch_here_for_param)))
1984 ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
1985 : S(S), FunLocation(FL), FunEndLocation(FEL),
1988 void setVerbose(
bool b) { Verbose =
b; }
1995 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
1996 for (
const auto &
Diag : Warnings) {
1997 S.Diag(
Diag.first.first,
Diag.first.second);
1998 for (
const auto &
Note :
Diag.second)
2003 void handleUnmatchedUnderlyingMutexes(SourceLocation Loc, SourceLocation DLoc,
2004 Name scopeName, StringRef Kind,
2005 Name expected, Name actual)
override {
2007 S.PDiag(diag::warn_unmatched_underlying_mutexes)
2008 << Kind << scopeName << expected << actual);
2009 Warnings.emplace_back(std::move(
Warning),
2010 makeManagedMismatchNoteForParam(DLoc));
2013 void handleExpectMoreUnderlyingMutexes(SourceLocation Loc,
2014 SourceLocation DLoc, Name scopeName,
2016 Name expected)
override {
2018 Loc, S.PDiag(diag::warn_expect_more_underlying_mutexes)
2019 << Kind << scopeName << expected);
2020 Warnings.emplace_back(std::move(
Warning),
2021 makeManagedMismatchNoteForParam(DLoc));
2024 void handleExpectFewerUnderlyingMutexes(SourceLocation Loc,
2025 SourceLocation DLoc, Name scopeName,
2027 Name actual)
override {
2029 Loc, S.PDiag(diag::warn_expect_fewer_underlying_mutexes)
2030 << Kind << scopeName << actual);
2031 Warnings.emplace_back(std::move(
Warning),
2032 makeManagedMismatchNoteForParam(DLoc));
2035 void handleInvalidLockExp(SourceLocation Loc)
override {
2038 Warnings.emplace_back(std::move(
Warning), getNotes());
2041 void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc,
2042 SourceLocation LocPreviousUnlock)
override {
2046 << Kind << LockName);
2047 Warnings.emplace_back(std::move(
Warning),
2048 makeUnlockedHereNote(LocPreviousUnlock, Kind));
2051 void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
2053 SourceLocation LocLocked,
2054 SourceLocation LocUnlock)
override {
2056 LocUnlock = FunLocation;
2058 LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch)
2059 << Kind << LockName << Received << Expected);
2060 Warnings.emplace_back(std::move(
Warning),
2061 makeLockedHereNote(LocLocked, Kind));
2064 void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked,
2065 SourceLocation LocDoubleLock)
override {
2067 LocDoubleLock = FunLocation;
2069 << Kind << LockName);
2070 Warnings.emplace_back(std::move(
Warning),
2071 makeLockedHereNote(LocLocked, Kind));
2074 void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
2075 SourceLocation LocLocked,
2076 SourceLocation LocEndOfScope,
2078 bool ReentrancyMismatch)
override {
2079 unsigned DiagID = 0;
2082 DiagID = diag::warn_lock_some_predecessors;
2085 DiagID = diag::warn_expecting_lock_held_on_loop;
2088 DiagID = diag::warn_no_unlock;
2091 DiagID = diag::warn_expecting_locked;
2095 LocEndOfScope = FunEndLocation;
2099 << ReentrancyMismatch);
2100 Warnings.emplace_back(std::move(
Warning),
2101 makeLockedHereNote(LocLocked, Kind));
2104 void handleExclusiveAndShared(StringRef Kind, Name LockName,
2105 SourceLocation Loc1,
2106 SourceLocation Loc2)
override {
2108 S.PDiag(diag::warn_lock_exclusive_and_shared)
2109 << Kind << LockName);
2111 << Kind << LockName);
2112 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2116 AccessKind AK, SourceLocation Loc)
override {
2117 unsigned DiagID = 0;
2124 DiagID = diag::warn_variable_requires_any_lock;
2131 DiagID = diag::warn_var_deref_requires_any_lock;
2134 llvm_unreachable(
"Only works for variables");
2139 Warnings.emplace_back(std::move(
Warning), getNotes());
2142 void handleMutexNotHeld(StringRef Kind,
const NamedDecl *D,
2145 Name *PossibleMatch)
override {
2146 unsigned DiagID = 0;
2147 if (PossibleMatch) {
2150 DiagID = diag::warn_variable_requires_lock_precise;
2153 DiagID = diag::warn_var_deref_requires_lock_precise;
2156 DiagID = diag::warn_fun_requires_lock_precise;
2159 DiagID = diag::warn_guarded_pass_by_reference;
2162 DiagID = diag::warn_pt_guarded_pass_by_reference;
2165 DiagID = diag::warn_guarded_return_by_reference;
2168 DiagID = diag::warn_pt_guarded_return_by_reference;
2171 DiagID = diag::warn_guarded_pass_pointer;
2174 DiagID = diag::warn_pt_guarded_pass_pointer;
2177 DiagID = diag::warn_guarded_return_pointer;
2180 DiagID = diag::warn_pt_guarded_return_pointer;
2190 S.PDiag(diag::note_guarded_by_declared_here)
2192 Warnings.emplace_back(std::move(
Warning), getNotes(
Note, VNote));
2194 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2198 DiagID = diag::warn_variable_requires_lock;
2201 DiagID = diag::warn_var_deref_requires_lock;
2204 DiagID = diag::warn_fun_requires_lock;
2207 DiagID = diag::warn_guarded_pass_by_reference;
2210 DiagID = diag::warn_pt_guarded_pass_by_reference;
2213 DiagID = diag::warn_guarded_return_by_reference;
2216 DiagID = diag::warn_pt_guarded_return_by_reference;
2219 DiagID = diag::warn_guarded_pass_pointer;
2222 DiagID = diag::warn_pt_guarded_pass_pointer;
2225 DiagID = diag::warn_guarded_return_pointer;
2228 DiagID = diag::warn_pt_guarded_return_pointer;
2236 S.PDiag(diag::note_guarded_by_declared_here));
2237 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2239 Warnings.emplace_back(std::move(
Warning), getNotes());
2243 void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
2244 SourceLocation Loc)
override {
2246 S.PDiag(diag::warn_acquire_requires_negative_cap)
2247 << Kind << LockName << Neg);
2248 Warnings.emplace_back(std::move(
Warning), getNotes());
2251 void handleNegativeNotHeld(
const NamedDecl *D, Name LockName,
2252 SourceLocation Loc)
override {
2254 Loc, S.PDiag(diag::warn_fun_requires_negative_cap) << D << LockName);
2255 Warnings.emplace_back(std::move(
Warning), getNotes());
2258 void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
2259 SourceLocation Loc)
override {
2261 << Kind << FunName << LockName);
2262 Warnings.emplace_back(std::move(
Warning), getNotes());
2265 void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
2266 SourceLocation Loc)
override {
2268 S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
2269 Warnings.emplace_back(std::move(
Warning), getNotes());
2272 void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc)
override {
2274 S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
2275 Warnings.emplace_back(std::move(
Warning), getNotes());
2278 void enterFunction(
const FunctionDecl* FD)
override {
2279 CurrentFunction = FD;
2282 void leaveFunction(
const FunctionDecl* FD)
override {
2283 CurrentFunction =
nullptr;
2304 ConsumedWarningsHandler(Sema &S) : S(S) {}
2307 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
2308 for (
const auto &
Diag : Warnings) {
2309 S.Diag(
Diag.first.first,
Diag.first.second);
2310 for (
const auto &
Note :
Diag.second)
2315 void warnLoopStateMismatch(SourceLocation Loc,
2316 StringRef VariableName)
override {
2323 void warnParamReturnTypestateMismatch(SourceLocation Loc,
2324 StringRef VariableName,
2325 StringRef ExpectedState,
2326 StringRef ObservedState)
override {
2329 diag::warn_param_return_typestate_mismatch) << VariableName <<
2330 ExpectedState << ObservedState);
2335 void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
2336 StringRef ObservedState)
override {
2339 diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
2344 void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
2345 StringRef TypeName)
override {
2347 diag::warn_return_typestate_for_unconsumable_type) << TypeName);
2352 void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
2353 StringRef ObservedState)
override {
2356 diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
2361 void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
2362 SourceLocation Loc)
override {
2365 diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
2370 void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
2371 StringRef State, SourceLocation Loc)
override {
2374 MethodName << VariableName << State);
2390 bool SuggestSuggestions;
2394 std::string listVariableGroupAsString(
2395 const VarDecl *VD,
const ArrayRef<const VarDecl *> &VarGroupForVD)
const {
2396 if (VarGroupForVD.size() <= 1)
2399 std::vector<StringRef> VarNames;
2400 auto PutInQuotes = [](StringRef S) -> std::string {
2401 return "'" + S.str() +
"'";
2404 for (
auto *
V : VarGroupForVD) {
2407 VarNames.push_back(
V->getName());
2409 if (VarNames.size() == 1) {
2410 return PutInQuotes(VarNames[0]);
2412 if (VarNames.size() == 2) {
2413 return PutInQuotes(VarNames[0]) +
" and " + PutInQuotes(VarNames[1]);
2415 assert(VarGroupForVD.size() > 3);
2416 const unsigned N = VarNames.size() -
2418 std::string AllVars =
"";
2420 for (
unsigned I = 0; I < N; ++I)
2421 AllVars.append(PutInQuotes(VarNames[I]) +
", ");
2422 AllVars.append(PutInQuotes(VarNames[N]) +
", and " +
2423 PutInQuotes(VarNames[N + 1]));
2428 UnsafeBufferUsageReporter(Sema &S,
bool SuggestSuggestions)
2429 : S(S), SuggestSuggestions(SuggestSuggestions) {}
2431 void handleUnsafeOperation(
const Stmt *Operation,
bool IsRelatedToDecl,
2432 ASTContext &Ctx)
override {
2435 unsigned MsgParam = 0;
2436 NamedDecl *D =
nullptr;
2437 if (
const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
2438 Loc = ASE->getBase()->getExprLoc();
2439 Range = ASE->getBase()->getSourceRange();
2441 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
2443 if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
2444 Op == BO_SubAssign) {
2454 }
else if (
const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
2456 if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
2465 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2469 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2471 D = ME->getMemberDecl();
2473 }
else if (
const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) {
2474 QualType destType = ECE->getType();
2475 bool destTypeComplete =
true;
2481 destTypeComplete = D->isCompleteDefinition();
2485 if (destTypeComplete) {
2487 QualType srcType = ECE->getSubExpr()->getType();
2497 if (
const auto *CE = dyn_cast<CXXMemberCallExpr>(
2498 ECE->getSubExpr()->IgnoreParens())) {
2499 D = CE->getMethodDecl();
2510 if (IsRelatedToDecl) {
2511 assert(!SuggestSuggestions &&
2512 "Variables blamed for unsafe buffer usage without suggestions!");
2513 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2516 S.Diag(Loc, diag::warn_unsafe_buffer_operation)
2517 << MsgParam << D <<
Range;
2519 S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam <<
Range;
2521 if (SuggestSuggestions) {
2522 S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled);
2527 void handleUnsafeLibcCall(
const CallExpr *
Call,
unsigned PrintfInfo,
2529 const Expr *UnsafeArg =
nullptr)
override {
2530 unsigned DiagID = diag::warn_unsafe_buffer_libc_call;
2531 if (PrintfInfo & 0x8) {
2535 DiagID = diag::warn_unsafe_buffer_format_attr_call;
2538 S.Diag(
Call->getBeginLoc(), DiagID)
2539 <<
Call->getDirectCallee()
2540 <<
Call->getSourceRange();
2541 if (PrintfInfo > 0) {
2543 UnsafeArg ? UnsafeArg->getSourceRange() :
Call->getSourceRange();
2544 S.Diag(R.
getBegin(), diag::note_unsafe_buffer_printf_call)
2549 void handleUnsafeOperationInContainer(
const Stmt *Operation,
2550 bool IsRelatedToDecl,
2551 ASTContext &Ctx)
override {
2554 unsigned MsgParam = 0;
2559 Loc = CtorExpr->getLocation();
2561 S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container);
2562 if (IsRelatedToDecl) {
2563 assert(!SuggestSuggestions &&
2564 "Variables blamed for unsafe buffer usage without suggestions!");
2565 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2569 void handleUnsafeVariableGroup(
const VarDecl *Variable,
2570 const VariableGroupsManager &VarGrpMgr,
2571 FixItList &&Fixes,
const Decl *D,
2572 const FixitStrategy &VarTargetTypes)
override {
2573 assert(!SuggestSuggestions &&
2574 "Unsafe buffer usage fixits displayed without suggestions!");
2575 S.Diag(
Variable->getLocation(), diag::warn_unsafe_buffer_variable)
2578 if (!Fixes.empty()) {
2580 "Fix-its are generated only for `NamedDecl`s");
2582 bool BriefMsg =
false;
2586 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Variable, &BriefMsg);
2587 unsigned FixItStrategy = 0;
2588 switch (VarTargetTypes.
lookup(Variable)) {
2596 assert(
false &&
"We support only std::span and std::array");
2601 BriefMsg ? diag::note_unsafe_buffer_variable_fixit_together
2602 : diag::note_unsafe_buffer_variable_fixit_group);
2605 FD << listVariableGroupAsString(Variable, VarGroupForVD)
2606 << (VarGroupForVD.size() > 1) << ND;
2607 for (
const auto &F : Fixes) {
2613 if (areDebugNotesRequested())
2614 for (
const DebugNote &
Note: DebugNotesByVar[Variable])
2615 S.Diag(
Note.first, diag::note_safe_buffer_debug_mode) <<
Note.second;
2619 void handleUnsafeUniquePtrArrayAccess(
const DynTypedNode &Node,
2620 bool IsRelatedToDecl,
2621 ASTContext &Ctx)
override {
2624 Loc = Node.
get<Stmt>()->getBeginLoc();
2625 S.Diag(Loc, diag::warn_unsafe_buffer_usage_unique_ptr_array_access)
2629 bool isSafeBufferOptOut(
const SourceLocation &Loc)
const override {
2630 return S.PP.isSafeBufferOptOut(S.getSourceManager(), Loc);
2634 return S.Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container, Loc);
2637 bool ignoreUnsafeBufferInLibcCall(
const SourceLocation &Loc)
const override {
2638 return S.Diags.isIgnored(diag::warn_unsafe_buffer_libc_call, Loc);
2641 bool ignoreUnsafeBufferInStaticSizedArray(
2642 const SourceLocation &Loc)
const override {
2643 return S.Diags.isIgnored(
2644 diag::warn_unsafe_buffer_usage_in_static_sized_array, Loc);
2651 getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,
2652 StringRef WSSuffix =
"")
const override {
2653 Preprocessor &PP = S.getPreprocessor();
2654 TokenValue ClangUnsafeBufferUsageTokens[] = {
2663 StringRef MacroName;
2667 if (MacroName.empty())
2668 MacroName =
"[[clang::unsafe_buffer_usage]]";
2669 return MacroName.str() + WSSuffix.str();
2680 enableCheckFallThrough = 1;
2681 enableCheckUnreachable = 0;
2682 enableThreadSafetyAnalysis = 0;
2683 enableConsumedAnalysis = 0;
2704template <
typename... Ts>
2707 return (!D.
isIgnored(Diags, Loc) || ...);
2712 NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),
2713 MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),
2714 NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
2715 NumUninitAnalysisBlockVisits(0),
2716 MaxUninitAnalysisBlockVisitsPerFunction(0) {
2724 using namespace diag;
2730 P.enableCheckUnreachable =
2731 PolicyOverrides.enableCheckUnreachable ||
2732 areAnyEnabled(D, Loc, warn_unreachable, warn_unreachable_break,
2733 warn_unreachable_return, warn_unreachable_loop_increment);
2735 P.enableThreadSafetyAnalysis = PolicyOverrides.enableThreadSafetyAnalysis ||
2738 P.enableConsumedAnalysis = PolicyOverrides.enableConsumedAnalysis ||
2743void sema::AnalysisBasedWarnings::clearOverrides() {
2744 PolicyOverrides.enableCheckUnreachable =
false;
2745 PolicyOverrides.enableConsumedAnalysis =
false;
2746 PolicyOverrides.enableThreadSafetyAnalysis =
false;
2751 S.
Diag(D.Loc, D.PD);
2754template <
typename Iterator>
2756 std::pair<Iterator, Iterator> PUDs) {
2758 if (PUDs.first == PUDs.second)
2761 for (
auto I = PUDs.first; I != PUDs.second; ++I) {
2762 for (
const Stmt *S : I->Stmts)
2770 for (
auto I = PUDs.first; I != PUDs.second; ++I) {
2772 if (llvm::all_of(D.Stmts, [&](
const Stmt *St) {
2773 const CFGBlock *Block = AC.getBlockForRegisteredExpression(St);
2777 if (Block && Analysis)
2778 if (!Analysis->isReachable(&AC.getCFG()->getEntry(), Block))
2782 S.
Diag(D.Loc, D.PD);
2786 for (
auto I = PUDs.first; I != PUDs.second; ++I)
2787 S.
Diag(I->Loc, I->PD);
2793 VarDeclPossiblyUnreachableDiags.emplace(VD, PUD);
2798 if (!llvm::is_contained(VarDeclPossiblyUnreachableDiags, VD))
2811 auto Range = VarDeclPossiblyUnreachableDiags.equal_range(VD);
2813 llvm::make_second_range(llvm::make_range(Range.first, Range.second));
2815 S, AC, std::make_pair(SecondRange.begin(), SecondRange.end()));
2822 llvm::function_ref<void(
const Decl *)> Callback;
2823 const Module *
const TUModule;
2827 const Module *
const TUModule)
2828 : Callback(Callback), TUModule(TUModule) {
2873namespace clang::lifetimes {
2875class LifetimeSafetyReporterImpl :
public LifetimeSafetyReporter {
2878 LifetimeSafetyReporterImpl(Sema &S) : S(S) {}
2880 void reportUseAfterFree(
const Expr *IssueExpr,
const Expr *UseExpr,
2881 SourceLocation FreeLoc, Confidence
C)
override {
2883 C == Confidence::Definite
2884 ? diag::warn_lifetime_safety_loan_expires_permissive
2885 : diag::warn_lifetime_safety_loan_expires_strict)
2887 S.
Diag(FreeLoc, diag::note_lifetime_safety_destroyed_here);
2888 S.
Diag(UseExpr->
getExprLoc(), diag::note_lifetime_safety_used_here)
2892 void reportUseAfterReturn(
const Expr *IssueExpr,
const Expr *EscapeExpr,
2893 SourceLocation ExpiryLoc, Confidence
C)
override {
2895 C == Confidence::Definite
2896 ? diag::warn_lifetime_safety_return_stack_addr_permissive
2897 : diag::warn_lifetime_safety_return_stack_addr_strict)
2900 S.
Diag(EscapeExpr->
getExprLoc(), diag::note_lifetime_safety_returned_here)
2904 void suggestAnnotation(SuggestionScope Scope,
2905 const ParmVarDecl *ParmToAnnotate,
2906 const Expr *EscapeExpr)
override {
2909 case SuggestionScope::CrossTU:
2910 DiagID = diag::warn_lifetime_safety_cross_tu_suggestion;
2912 case SuggestionScope::IntraTU:
2913 DiagID = diag::warn_lifetime_safety_intra_tu_suggestion;
2923 " [[clang::lifetimebound]]");
2926 diag::note_lifetime_safety_suggestion_returned_here)
2939 llvm::TimeTraceScope TimeProfile(
"LifetimeSafetyTUAnalysis");
2942 lifetimes::LifetimeSafetyReporterImpl Reporter(S);
2943 for (
auto *Node : llvm::post_order(&CG)) {
2945 dyn_cast_or_null<clang::FunctionDecl>(Node->getDecl());
2958 runLifetimeSafetyAnalysis(AC, &Reporter, LSStats, S.
CollectStats);
2976 bool UnsafeBufferUsageCanEmitSuggestions = S.getLangOpts().CPlusPlus20;
2977 bool UnsafeBufferUsageShouldEmitSuggestions =
2978 UnsafeBufferUsageCanEmitSuggestions &&
2979 DiagOpts.ShowSafeBufferUsageSuggestions;
2980 bool UnsafeBufferUsageShouldSuggestSuggestions =
2981 UnsafeBufferUsageCanEmitSuggestions &&
2982 !DiagOpts.ShowSafeBufferUsageSuggestions;
2983 UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions);
2986 auto CallAnalyzers = [&](
const Decl *Node) ->
void {
2987 if (Node->hasAttr<UnsafeBufferUsageAttr>())
2991 if (!Diags.
isIgnored(diag::warn_unsafe_buffer_operation,
2992 Node->getBeginLoc()) ||
2993 !Diags.
isIgnored(diag::warn_unsafe_buffer_variable,
2994 Node->getBeginLoc()) ||
2995 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2996 Node->getBeginLoc()) ||
2997 !Diags.
isIgnored(diag::warn_unsafe_buffer_libc_call,
2998 Node->getBeginLoc())) {
3000 UnsafeBufferUsageShouldEmitSuggestions);
3009 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
3012 S.getLangOpts().CPlusPlus )) {
3014 .TraverseTranslationUnitDecl(TU);
3017 if (S.getLangOpts().EnableLifetimeSafety && S.getLangOpts().CPlusPlus &&
3018 S.getLangOpts().EnableLifetimeSafetyTUAnalysis)
3044 if (S.hasUncompilableErrorOccurred()) {
3066 bool EnableLifetimeSafetyAnalysis =
3067 S.getLangOpts().EnableLifetimeSafety &&
3068 !S.getLangOpts().EnableLifetimeSafetyTUAnalysis;
3076 if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||
3077 P.enableConsumedAnalysis || EnableLifetimeSafetyAnalysis) {
3090 if (EnableLifetimeSafetyAnalysis)
3094 std::optional<LogicalErrorHandler> LEH;
3095 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->
getBeginLoc())) {
3105 if (P.enableCheckFallThrough) {
3106 const CheckFallThroughDiagnostics &CD =
3111 ? CheckFallThroughDiagnostics::MakeForLambda()
3113 ? CheckFallThroughDiagnostics::MakeForCoroutine(D)
3114 : CheckFallThroughDiagnostics::MakeForFunction(S, D)));
3119 if (P.enableCheckUnreachable) {
3132 if (P.enableThreadSafetyAnalysis) {
3135 threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
3137 Reporter.setIssueBetaWarnings(
true);
3139 Reporter.setVerbose(
true);
3142 &S.ThreadSafetyDeclCache);
3143 Reporter.emitDiagnostics();
3147 if (P.enableConsumedAnalysis) {
3148 consumed::ConsumedWarningsHandler WarningHandler(S);
3159 UninitValsDiagReporter reporter(S);
3166 ++NumUninitAnalysisFunctions;
3169 MaxUninitAnalysisVariablesPerFunction =
3170 std::max(MaxUninitAnalysisVariablesPerFunction,
3172 MaxUninitAnalysisBlockVisitsPerFunction =
3173 std::max(MaxUninitAnalysisBlockVisitsPerFunction,
3181 if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {
3183 lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);
3189 if (S.getLangOpts().ObjC && !S.getLangOpts().CPlusPlus &&
3190 shouldAnalyzeCalledOnceParameters(Diags, D->
getBeginLoc())) {
3192 CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);
3195 shouldAnalyzeCalledOnceConventions(Diags, D->
getBeginLoc()));
3199 bool FallThroughDiagFull =
3201 bool FallThroughDiagPerFunction = !Diags.
isIgnored(
3202 diag::warn_unannotated_fallthrough_per_function, D->
getBeginLoc());
3203 if (FallThroughDiagFull || FallThroughDiagPerFunction ||
3208 if (S.getLangOpts().ObjCWeak &&
3214 if (!Diags.
isIgnored(diag::warn_infinite_recursive_function,
3216 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
3223 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
3229 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->
getBeginLoc())) {
3238 ++NumFunctionsAnalyzed;
3242 NumCFGBlocks += cfg->getNumBlockIDs();
3243 MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
3244 cfg->getNumBlockIDs());
3246 ++NumFunctionsWithBadCFGs;
3252 llvm::errs() <<
"\n*** Analysis Based Warnings Stats:\n";
3254 unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
3255 unsigned AvgCFGBlocksPerFunction =
3256 !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
3257 llvm::errs() << NumFunctionsAnalyzed <<
" functions analyzed ("
3258 << NumFunctionsWithBadCFGs <<
" w/o CFGs).\n"
3259 <<
" " << NumCFGBlocks <<
" CFG blocks built.\n"
3260 <<
" " << AvgCFGBlocksPerFunction
3261 <<
" average CFG blocks per function.\n"
3262 <<
" " << MaxCFGBlocksPerFunction
3263 <<
" max CFG blocks per function.\n";
3265 unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
3266 : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
3267 unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
3268 : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
3269 llvm::errs() << NumUninitAnalysisFunctions
3270 <<
" functions analyzed for uninitialiazed variables\n"
3271 <<
" " << NumUninitAnalysisVariables <<
" variables analyzed.\n"
3272 <<
" " << AvgUninitVariablesPerFunction
3273 <<
" average variables per function.\n"
3274 <<
" " << MaxUninitAnalysisVariablesPerFunction
3275 <<
" max variables per function.\n"
3276 <<
" " << NumUninitAnalysisBlockVisits <<
" block visits.\n"
3277 <<
" " << AvgUninitBlockVisitsPerFunction
3278 <<
" average block visits per function.\n"
3279 <<
" " << MaxUninitAnalysisBlockVisitsPerFunction
3280 <<
" 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
BuildOptions & setAllAlwaysAdd()
BuildOptions & setAlwaysAdd(Stmt::StmtClass stmtClass, bool val=true)
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Represents a call to a member function that may be written either with member call syntax (e....
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
A C++ throw-expression (C++ [except.throw]).
const Expr * getSubExpr() const
SourceLocation getThrowLoc() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
ExprIterator arg_iterator
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
The AST-based call graph.
void addToCallGraph(Decl *D)
Populate the call graph with the functions in the given declaration.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getBegin() const
ConditionalOperator - The ?
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
Expr * getCond() const
getCond - Return the expression representing the condition for the ?
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
ConstEvaluatedExprVisitor - This class visits 'const Expr *'s.
void enqueueBlock(const CFGBlock *Block)
const CFGBlock * dequeue()
bool isFunctionOrMethod() const
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
SourceLocation getEndLoc() const LLVM_READONLY
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Module * getOwningModule() const
Get the module that owns this declaration (for visibility purposes).
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
SourceLocation getLocation() const
DeclContext * getDeclContext()
SourceLocation getBeginLoc() const LLVM_READONLY
DeclContext * getLexicalDeclContext()
getLexicalDeclContext - The declaration context where this Decl was lexically declared (LexicalDC).
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
OverloadedOperatorKind getCXXOverloadedOperator() const
If this name is the name of an overloadable operator in C++ (e.g., operator+), retrieve the kind of o...
SourceLocation getBeginLoc() const LLVM_READONLY
TypeSourceInfo * getTypeSourceInfo() const
Options for controlling the compiler diagnostics engine.
Concrete class used by the front-end to report problems and issues.
bool isLastDiagnosticIgnored() const
Determine whether the previous diagnostic was ignored.
bool getIgnoreAllWarnings() const
DiagnosticOptions & getDiagnosticOptions() const
Retrieve the diagnostic options.
bool isIgnored(unsigned DiagID, SourceLocation Loc) const
Determine whether the diagnostic is known to be ignored.
bool getSuppressSystemWarnings() const
const T * get() const
Retrieve the stored node as type T.
SourceRange getSourceRange(bool IncludeQualifier=false) const
For nodes which represent textual entities in the source code, return their SourceRange.
virtual bool TraverseDecl(MaybeConst< Decl > *D)
bool ShouldVisitTemplateInstantiations
bool ShouldVisitImplicitCode
void VisitDeclRefExpr(PTR(DeclRefExpr) E)
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
static FixItHint CreateRemoval(CharSourceRange RemoveRange)
Create a code modification hint that removes the given source range.
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
Kind lookup(const VarDecl *VD) const
Represents a function declaration or definition.
FunctionDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
bool doesThisDeclarationHaveABody() const
Returns whether this specific declaration of the function has a body.
SourceRange getExceptionSpecSourceRange() const
Attempt to compute an informative source range covering the function exception specification,...
@ TK_MemberSpecialization
TemplatedKind getTemplatedKind() const
What kind of templated function this is.
FunctionDecl * getDefinition()
Get the definition for this declaration.
bool isCPUDispatchMultiVersion() const
True if this function is a multiversioned dispatch function as a part of the cpu_specific/cpu_dispatc...
Represents a prototype with parameter type info, e.g.
FunctionType - C99 6.7.5.3 - Function Declarators.
IfStmt - This represents an if/then/else.
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
CXXMethodDecl * getCallOperator() const
Retrieve the function call operator associated with this lambda expression.
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)
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
bool isInMainFile(SourceLocation Loc) const
Returns whether the PresumedLoc for a given SourceLocation is in the main file.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Stmt - This represents one statement.
SourceLocation getEndLoc() const LLVM_READONLY
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SourceLocation getBeginLoc() const LLVM_READONLY
Stores token information for comparing actual tokens with predefined values.
The top declaration context.
QualType getType() const
Return the type wrapped by this type source info.
bool isBlockPointerType() const
bool isPointerType() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
const T * castAs() const
Member-template castAs<specific type>.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
TagDecl * getAsTagDecl() const
Retrieves the TagDecl that this type refers to, either because the type is a TagType or because it is...
const T * getAs() const
Member-template getAs<specific type>'.
Expr * getSubExpr() const
A use of a variable, which might be uninitialized.
const Expr * getUser() const
Get the expression containing the uninitialized use.
SmallVectorImpl< Branch >::const_iterator branch_iterator
branch_iterator branch_end() const
bool isConstPtrUse() const
bool isConstRefOrPtrUse() const
bool isConstRefUse() const
branch_iterator branch_begin() const
Branches which inevitably result in the variable being used uninitialized.
@ Always
The use is always uninitialized.
@ AfterDecl
The use is uninitialized the first time it is reached after we reach the variable's declaration.
@ Maybe
The use might be uninitialized.
@ AfterCall
The use is uninitialized the first time it is reached after the function is called.
@ Sometimes
The use is uninitialized whenever a certain branch is taken.
Kind getKind() const
Get the kind of uninitialized use.
The interface that lets the caller handle unsafe buffer usage analysis results by overriding this cla...
Represents a variable declaration or definition.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
VarDecl * getDefinition(ASTContext &)
Get the real (not just tentative) definition for this declaration.
const Expr * getInit() const
virtual VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm=nullptr) const =0
Returns the set of variables (including Var) that need to be fixed together in one step.
A class that handles the analysis of uniqueness violations.
void issueWarningsForRegisteredVarDecl(VarDecl *VD)
void IssueWarnings(Policy P, FunctionScopeInfo *fscope, const Decl *D, QualType BlockType)
void registerVarDeclWarning(VarDecl *VD, PossiblyUnreachableDiag PUD)
AnalysisBasedWarnings(Sema &s)
Policy getPolicyInEffectAt(SourceLocation Loc)
Represents a simple identification of a weak object.
Retains information about a function, method, or block that is currently being parsed.
bool HasFallthroughStmt
Whether there is a fallthrough statement in this function.
SmallVector< WeakUseTy, 4 > WeakUseVector
Used to collect uses of a particular weak object in a function body.
SmallVector< PossiblyUnreachableDiag, 4 > PossiblyUnreachableDiags
A list of PartialDiagnostics created but delayed within the current function scope.
llvm::SmallDenseMap< WeakObjectProfileTy, WeakUseVector, 8, WeakObjectProfileTy::DenseMapInfo > WeakObjectUseMap
Used to collect all uses of weak objects in a function body.
const WeakObjectUseMap & getWeakObjectUses() const
InterProceduralData aims to be a storage of whatever data should be passed between analyses of differ...
CalledOnceInterProceduralData CalledOnceData
std::list< DelayedDiag > DiagList
std::pair< PartialDiagnosticAt, OptionalNotes > DelayedDiag
SmallVector< PartialDiagnosticAt, 1 > OptionalNotes
uint32_t Variable
Boolean variables are represented as positive integers.
bool LE(InterpState &S, CodePtr OpPC)
void printStats(const LifetimeSafetyStats &Stats)
Utility function to print missing origin stats.
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, LifetimeSafetyStats &Stats, bool CollectStats)
The main entry point for the analysis.
void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP, Callback &CB)
unsigned ScanReachableFromBlock(const CFGBlock *Start, llvm::BitVector &Reachable)
ScanReachableFromBlock - Mark all blocks reachable from Start.
UnreachableKind
Classifications of unreachable code.
LockKind getLockKindFromAccessKind(AccessKind AK)
Helper function that returns a LockKind required for the given level of access.
LockErrorKind
This enum distinguishes between different situations where we warn due to inconsistent locking.
@ LEK_NotLockedAtEndOfFunction
Expecting a capability to be held at the end of function.
@ LEK_LockedSomePredecessors
A capability is locked in some but not all predecessors of a CFGBlock.
@ LEK_LockedAtEndOfFunction
A capability is still locked at the end of a function.
@ LEK_LockedSomeLoopIterations
A capability is locked for some but not all loop iterations.
AccessKind
This enum distinguishes between different ways to access (read or write) a variable.
LockKind
This enum distinguishes between different kinds of lock actions.
void runThreadSafetyAnalysis(AnalysisDeclContext &AC, ThreadSafetyHandler &Handler, BeforeSet **Bset)
Check a function's CFG for thread-safety violations.
ProtectedOperationKind
This enum distinguishes between different kinds of operations that may need to be protected by locks.
@ POK_PtPassByRef
Passing a pt-guarded variable by reference.
@ POK_PassPointer
Passing pointer to a guarded variable.
@ POK_VarDereference
Dereferencing a variable (e.g. p in *p = 5;)
@ POK_PassByRef
Passing a guarded variable by reference.
@ POK_ReturnByRef
Returning a guarded variable by reference.
@ POK_PtPassPointer
Passing a pt-guarded pointer.
@ POK_PtReturnPointer
Returning a pt-guarded pointer.
@ POK_VarAccess
Reading or writing a variable (e.g. x in x = 5;)
@ POK_FunctionCall
Making a function call (e.g. fool())
@ POK_ReturnPointer
Returning pointer to a guarded variable.
@ POK_PtReturnByRef
Returning a pt-guarded variable by reference.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
bool isTemplateInstantiation(TemplateSpecializationKind Kind)
Determine whether this template specialization kind refers to an instantiation of an entity (as oppos...
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
bool hasSpecificAttr(const Container &container)
@ If
'if' clause, allowed on all the Compute Constructs, Data Constructs, Executable Constructs,...
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ Parameter
The parameter type of a method or function.
void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats)
void checkCalledOnceParameters(AnalysisDeclContext &AC, CalledOnceCheckHandler &Handler, bool CheckConventionalParameters)
Check given CFG for 'called once' parameter violations.
std::pair< SourceLocation, PartialDiagnostic > PartialDiagnosticAt
A partial diagnostic along with the source location where this diagnostic occurs.
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
A worklist implementation for backward dataflow analysis.
void enqueuePredecessors(const CFGBlock *Block)
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.
unsigned NumVariablesAnalyzed
A structure to hold the statistics related to LifetimeAnalysis.