48#include "llvm/ADT/ArrayRef.h"
49#include "llvm/ADT/BitVector.h"
50#include "llvm/ADT/DenseMap.h"
51#include "llvm/ADT/MapVector.h"
52#include "llvm/ADT/STLFunctionalExtras.h"
53#include "llvm/ADT/SmallVector.h"
54#include "llvm/ADT/StringRef.h"
55#include "llvm/Support/Debug.h"
70 SourceRange PreviousSilenceableCondVal;
73 UnreachableCodeHandler(Sema &
s) : S(
s) {}
76 SourceRange SilenceableCondVal, SourceRange R1,
77 SourceRange R2,
bool HasFallThroughAttr)
override {
81 if (HasFallThroughAttr &&
82 !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr,
88 if (PreviousSilenceableCondVal.isValid() &&
90 PreviousSilenceableCondVal == SilenceableCondVal)
92 PreviousSilenceableCondVal = SilenceableCondVal;
94 unsigned diag = diag::warn_unreachable;
97 diag = diag::warn_unreachable_break;
100 diag = diag::warn_unreachable_return;
103 diag = diag::warn_unreachable_loop_increment;
109 S.Diag(L, diag) << R1 << R2;
112 if (
Open.isValid()) {
113 SourceLocation Close = SilenceableCondVal.
getEnd();
114 Close = S.getLocForEndOfToken(Close);
116 S.Diag(
Open, diag::note_unreachable_silence)
137 UnreachableCodeHandler UC(S);
147 LogicalErrorHandler(Sema &S) : S(S) {}
149 static bool HasMacroID(
const Expr *E) {
154 for (
const Stmt *SubStmt : E->
children())
155 if (
const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt))
156 if (HasMacroID(SubExpr))
162 void logicAlwaysTrue(
const BinaryOperator *B,
bool isAlwaysTrue)
override {
166 unsigned DiagID = isAlwaysTrue
167 ? diag::warn_tautological_negation_or_compare
168 : diag::warn_tautological_negation_and_compare;
173 void compareAlwaysTrue(
const BinaryOperator *B,
174 bool isAlwaysTrueOrFalse)
override {
179 S.Diag(B->
getExprLoc(), diag::warn_tautological_overlap_comparison)
180 << DiagRange << isAlwaysTrueOrFalse;
183 void compareBitwiseEquality(
const BinaryOperator *B,
184 bool isAlwaysTrue)
override {
189 S.Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_always)
190 << DiagRange << isAlwaysTrue;
193 void compareBitwiseOr(
const BinaryOperator *B)
override {
198 S.Diag(B->
getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;
201 static bool hasActiveDiagnostics(DiagnosticsEngine &Diags,
202 SourceLocation Loc) {
203 return !Diags.
isIgnored(diag::warn_tautological_overlap_comparison, Loc) ||
204 !Diags.
isIgnored(diag::warn_comparison_bitwise_or, Loc) ||
205 !Diags.
isIgnored(diag::warn_tautological_negation_and_compare, Loc);
219 for (
const auto &B :
Block) {
233 if (isa_and_nonnull<TemplateSpecializationType>(NNS.getAsType()))
249 bool foundRecursion =
false;
254 WorkList.push_back(&cfg->
getEntry());
256 while (!WorkList.empty()) {
259 for (
auto I =
Block->succ_begin(), E =
Block->succ_end(); I != E; ++I) {
261 if (!Visited.insert(SuccBlock).second)
265 if (ExitID == SuccBlock->getBlockID())
270 foundRecursion =
true;
274 WorkList.push_back(SuccBlock);
278 return foundRecursion;
314 Stack.push_back(&ThrowBlock);
317 while (!Stack.empty()) {
318 CFGBlock &UnwindBlock = *Stack.pop_back_val();
320 for (
auto &Succ : UnwindBlock.
succs()) {
321 if (!Succ.isReachable() || Queued[Succ->getBlockID()])
328 dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
329 QualType Caught = Catch->getCaughtType();
336 Stack.push_back(Succ);
337 Queued[Succ->getBlockID()] =
true;
351 if (!Reachable[B->getBlockID()])
354 std::optional<CFGStmt> S = E.getAs<
CFGStmt>();
357 if (
auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))
367 S.
Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
373 getAs<FunctionProtoType>())
398 if (FPT->isNothrow() || FD->
hasAttr<NoThrowAttr>())
407 if (
auto *FD = dyn_cast<FunctionDecl>(DRef->getDecl()))
408 return FD->isNoReturn();
427struct TransferFunctions :
public StmtVisitor<TransferFunctions> {
429 std::optional<bool> AllValuesAreNoReturn;
431 TransferFunctions(
const VarDecl *VD) : Var(VD) {}
433 void reset() { AllValuesAreNoReturn = std::nullopt; }
435 void VisitDeclStmt(DeclStmt *DS) {
436 for (
auto *DI : DS->
decls())
437 if (
auto *VD = dyn_cast<VarDecl>(DI))
438 if (VarDecl *Def = VD->getDefinition())
443 void VisitUnaryOperator(UnaryOperator *UO) {
447 if (DRef->getDecl() == Var)
448 AllValuesAreNoReturn =
false;
452 void VisitBinaryOperator(BinaryOperator *BO) {
455 if (DRef->getDecl() == Var)
459 void VisitCallExpr(CallExpr *CE) {
462 const Expr *Arg = *I;
465 if (
auto VD = dyn_cast<VarDecl>(DRef->getDecl()))
466 if (VD->getDefinition() == Var)
467 AllValuesAreNoReturn =
false;
493 using MapTy = llvm::DenseMap<const CFGBlock *, std::optional<bool>>;
494 using ValueTy = MapTy::value_type;
496 BlocksToCheck[&VarBlk] = std::nullopt;
497 const auto BlockSatisfiesCondition = [](ValueTy Item) {
498 return Item.getSecond().value_or(
false);
501 TransferFunctions TF(VD);
503 llvm::DenseSet<const CFGBlock *> Visited;
506 if (Visited.contains(B))
512 if (std::optional<CFGStmt> cs = ri->getAs<
CFGStmt>()) {
513 const Stmt *S = cs->getStmt();
515 TF.Visit(
const_cast<Stmt *
>(S));
516 if (TF.AllValuesAreNoReturn) {
517 if (!TF.AllValuesAreNoReturn.value())
519 BlocksToCheck[B] =
true;
526 if (llvm::all_of(BlocksToCheck, BlockSatisfiesCondition))
531 if (!BlocksToCheck[B]) {
533 BlocksToCheck.erase(B);
534 for (
const auto &PredBlk : B->preds())
535 if (!BlocksToCheck.contains(PredBlk))
536 BlocksToCheck[PredBlk] = std::nullopt;
579 for (
const auto *B : *cfg) {
580 if (!live[B->getBlockID()]) {
581 if (B->preds().empty()) {
582 const Stmt *Term = B->getTerminatorStmt();
583 if (isa_and_nonnull<CXXTryStmt>(Term))
595 bool HasLiveReturn =
false;
596 bool HasFakeEdge =
false;
597 bool HasPlainEdge =
false;
598 bool HasAbnormalEdge =
false;
616 HasAbnormalEdge =
true;
625 for ( ; ri != re ; ++ri)
633 HasAbnormalEdge =
true;
644 HasLiveReturn =
true;
658 HasLiveReturn =
true;
662 HasAbnormalEdge =
true;
666 HasAbnormalEdge =
true;
669 if (
auto *
Call = dyn_cast<CallExpr>(S)) {
670 const Expr *Callee =
Call->getCallee();
671 if (Callee->getType()->isPointerType())
673 dyn_cast<DeclRefExpr>(Callee->IgnoreParenImpCasts()))
674 if (
auto *VD = dyn_cast<VarDecl>(DeclRef->getDecl()))
676 HasAbnormalEdge =
true;
688 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
698struct CheckFallThroughDiagnostics {
699 unsigned diag_FallThrough_HasNoReturn = 0;
700 unsigned diag_FallThrough_ReturnsNonVoid = 0;
701 unsigned diag_NeverFallThroughOrReturn = 0;
703 SourceLocation FuncLoc;
705 static CheckFallThroughDiagnostics MakeForFunction(Sema &S,
707 CheckFallThroughDiagnostics D;
708 D.FuncLoc =
Func->getLocation();
709 D.diag_FallThrough_HasNoReturn = diag::warn_noreturn_has_return_expr;
710 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
714 bool isVirtualMethod =
false;
715 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(
Func))
716 isVirtualMethod =
Method->isVirtual();
720 if (
const FunctionDecl *
Function = dyn_cast<FunctionDecl>(
Func)) {
724 D.diag_FallThrough_ReturnsNonVoid = diag::ext_main_no_return;
729 D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function;
731 D.FunKind = diag::FalloffFunctionKind::Function;
735 static CheckFallThroughDiagnostics MakeForCoroutine(
const Decl *
Func) {
736 CheckFallThroughDiagnostics D;
737 D.FuncLoc =
Func->getLocation();
738 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
739 D.FunKind = diag::FalloffFunctionKind::Coroutine;
743 static CheckFallThroughDiagnostics MakeForBlock() {
744 CheckFallThroughDiagnostics D;
745 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;
746 D.diag_FallThrough_ReturnsNonVoid = diag::err_falloff_nonvoid;
747 D.FunKind = diag::FalloffFunctionKind::Block;
751 static CheckFallThroughDiagnostics MakeForLambda() {
752 CheckFallThroughDiagnostics D;
753 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;
754 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;
755 D.FunKind = diag::FalloffFunctionKind::Lambda;
759 bool checkDiagnostics(DiagnosticsEngine &D,
bool ReturnsVoid,
760 bool HasNoReturn)
const {
761 if (FunKind == diag::FalloffFunctionKind::Function) {
762 return (ReturnsVoid ||
763 D.
isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&
765 D.
isIgnored(diag::warn_noreturn_has_return_expr, FuncLoc)) &&
767 D.
isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));
769 if (FunKind == diag::FalloffFunctionKind::Coroutine) {
770 return (ReturnsVoid ||
771 D.
isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&
775 return ReturnsVoid && !HasNoReturn;
787 const CheckFallThroughDiagnostics &CD,
790 bool ReturnsVoid =
false;
791 bool HasNoReturn =
false;
793 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
794 if (
const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
795 ReturnsVoid = CBody->getFallthroughHandler() !=
nullptr;
797 ReturnsVoid = FD->getReturnType()->isVoidType();
798 HasNoReturn = FD->isNoReturn() || FD->hasAttr<InferredNoReturnAttr>();
800 else if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
801 ReturnsVoid = MD->getReturnType()->isVoidType();
802 HasNoReturn = MD->hasAttr<NoReturnAttr>();
807 if (FT->getReturnType()->isVoidType())
809 if (FT->getNoReturnAttr())
817 if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
833 if (CD.diag_FallThrough_HasNoReturn)
834 S.
Diag(RBrace, CD.diag_FallThrough_HasNoReturn) << CD.FunKind;
835 }
else if (!ReturnsVoid && CD.diag_FallThrough_ReturnsNonVoid) {
839 if (
const auto *CS = dyn_cast<CompoundStmt>(Body);
840 CS && !CS->body_empty()) {
841 const Stmt *LastStmt = CS->body_back();
843 if (
const auto *EWC = dyn_cast<ExprWithCleanups>(LastStmt)) {
844 LastStmt = EWC->getSubExpr();
846 if (
const auto *CE = dyn_cast<CallExpr>(LastStmt)) {
848 Callee && Callee->hasAttr<InferredNoReturnAttr>()) {
859 S.
Diag(RBrace, CD.diag_FallThrough_ReturnsNonVoid)
860 << CD.FunKind << NotInAllControlPaths;
864 if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
865 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
866 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
867 }
else if (
const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
868 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
870 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
889 const DeclRefExpr *Needle;
892 typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited;
894 ContainsReference(ASTContext &Context,
const DeclRefExpr *Needle)
895 : Inherited(Context), FoundReference(
false), Needle(Needle) {}
897 void VisitExpr(
const Expr *E) {
902 Inherited::VisitExpr(E);
905 void VisitDeclRefExpr(
const DeclRefExpr *E) {
907 FoundReference =
true;
912 bool doesContainReference()
const {
return FoundReference; }
920 S.
Diag(VD->
getLocation(), diag::note_block_var_fixit_add_initialization)
941 S.
Diag(Loc, diag::note_var_fixit_add_initialization) << VD->
getDeclName()
949 const Stmt *Else,
bool CondVal,
973 bool IsCapturedByBlock) {
974 bool Diagnosed =
false;
1006 const Stmt *Term = I->Terminator;
1016 int RemoveDiagKind = -1;
1017 const char *FixitStr =
1018 S.
getLangOpts().CPlusPlus ? (I->Output ?
"true" :
"false")
1019 : (I->Output ?
"1" :
"0");
1022 switch (Term ? Term->
getStmtClass() : Stmt::DeclStmtClass) {
1029 case Stmt::IfStmtClass: {
1036 I->Output, Fixit1, Fixit2);
1039 case Stmt::ConditionalOperatorClass: {
1046 I->Output, Fixit1, Fixit2);
1049 case Stmt::BinaryOperatorClass: {
1057 if ((BO->
getOpcode() == BO_LAnd && I->Output) ||
1058 (BO->
getOpcode() == BO_LOr && !I->Output))
1069 case Stmt::WhileStmtClass:
1076 case Stmt::ForStmtClass:
1086 case Stmt::CXXForRangeStmtClass:
1087 if (I->Output == 1) {
1099 case Stmt::DoStmtClass:
1102 Range =
cast<DoStmt>(Term)->getCond()->getSourceRange();
1108 case Stmt::CaseStmtClass:
1113 case Stmt::DefaultStmtClass:
1120 S.
Diag(Range.getBegin(), diag::warn_sometimes_uninit_var)
1121 << VD->
getDeclName() << IsCapturedByBlock << DiagKind
1122 << Str << I->Output << Range;
1125 if (RemoveDiagKind != -1)
1127 << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
1161 bool alwaysReportSelfInit =
false) {
1175 if (!alwaysReportSelfInit && DRE ==
Initializer->IgnoreParenImpCasts())
1178 ContainsReference CR(S.
Context, DRE);
1180 if (CR.doesContainReference()) {
1181 S.
Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
1192 diag::warn_uninit_byref_blockvar_captured_by_block)
1212 FallthroughMapper(Sema &S) : FoundSwitchStatements(
false), S(S) {
1213 ShouldWalkTypesOfTypeLocs =
false;
1216 bool foundSwitchStatements()
const {
return FoundSwitchStatements; }
1218 void markFallthroughVisited(
const AttributedStmt *Stmt) {
1219 bool Found = FallthroughStmts.erase(Stmt);
1224 typedef llvm::SmallPtrSet<const AttributedStmt *, 8> AttrStmts;
1226 const AttrStmts &getFallthroughStmts()
const {
return FallthroughStmts; }
1228 void fillReachableBlocks(CFG *Cfg) {
1229 assert(ReachableBlocks.empty() &&
"ReachableBlocks already filled");
1230 std::deque<const CFGBlock *> BlockQueue;
1232 ReachableBlocks.insert(&Cfg->
getEntry());
1233 BlockQueue.push_back(&Cfg->
getEntry());
1238 for (
const auto *B : *Cfg) {
1239 const Stmt *L = B->getLabel();
1240 if (isa_and_nonnull<SwitchCase>(L) && ReachableBlocks.insert(B).second)
1241 BlockQueue.push_back(B);
1244 while (!BlockQueue.empty()) {
1245 const CFGBlock *P = BlockQueue.front();
1246 BlockQueue.pop_front();
1247 for (
const CFGBlock *B : P->
succs()) {
1248 if (B && ReachableBlocks.insert(B).second)
1249 BlockQueue.push_back(B);
1254 bool checkFallThroughIntoBlock(
const CFGBlock &B,
int &AnnotatedCnt,
1255 bool IsTemplateInstantiation) {
1256 assert(!ReachableBlocks.empty() &&
"ReachableBlocks empty");
1258 int UnannotatedCnt = 0;
1262 while (!BlockQueue.empty()) {
1263 const CFGBlock *P = BlockQueue.
front();
1264 BlockQueue.pop_front();
1269 if (isa_and_nonnull<SwitchStmt>(Term))
1272 const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->
getLabel());
1276 const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->
getLabel());
1280 if (!ReachableBlocks.count(P)) {
1281 for (
const CFGElement &Elem : llvm::reverse(*P)) {
1282 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) {
1283 if (
const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
1287 if (!IsTemplateInstantiation)
1288 S.Diag(AS->getBeginLoc(),
1289 diag::warn_unreachable_fallthrough_attr);
1290 markFallthroughVisited(AS);
1309 if (
const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {
1310 markFallthroughVisited(AS);
1318 std::back_inserter(BlockQueue));
1324 return !!UnannotatedCnt;
1327 bool VisitAttributedStmt(AttributedStmt *S)
override {
1328 if (asFallThroughAttr(S))
1329 FallthroughStmts.insert(S);
1333 bool VisitSwitchStmt(SwitchStmt *S)
override {
1334 FoundSwitchStatements =
true;
1340 bool TraverseDecl(Decl *D)
override {
return true; }
1343 bool TraverseLambdaExpr(
LambdaExpr *LE)
override {
1345 for (
const auto C : zip(
LE->captures(),
LE->capture_inits()))
1346 TraverseLambdaCapture(LE, &std::get<0>(
C), std::get<1>(
C));
1352 static const AttributedStmt *asFallThroughAttr(
const Stmt *S) {
1353 if (
const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
1360 static const Stmt *
getLastStmt(
const CFGBlock &B) {
1363 for (
const CFGElement &Elem : llvm::reverse(B))
1364 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
1365 return CS->getStmt();
1369 if (
const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.
getLabel()))
1376 bool FoundSwitchStatements;
1377 AttrStmts FallthroughStmts;
1379 llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
1386 tok::l_square, tok::l_square,
1388 tok::r_square, tok::r_square
1394 tok::r_square, tok::r_square
1399 StringRef MacroName;
1400 if (PreferClangAttr)
1402 if (MacroName.empty())
1404 if (MacroName.empty() && !PreferClangAttr)
1406 if (MacroName.empty()) {
1407 if (!PreferClangAttr)
1408 MacroName =
"[[fallthrough]]";
1410 MacroName =
"[[clang::fallthrough]]";
1412 MacroName =
"__attribute__((fallthrough))";
1419 FallthroughMapper FM(S);
1420 FM.TraverseStmt(AC.
getBody());
1422 if (!FM.foundSwitchStatements())
1425 if (PerFunction && FM.getFallthroughStmts().empty())
1433 FM.fillReachableBlocks(Cfg);
1435 for (
const CFGBlock *B : llvm::reverse(*Cfg)) {
1438 if (!isa_and_nonnull<SwitchCase>(Label))
1443 bool IsTemplateInstantiation =
false;
1445 IsTemplateInstantiation = Function->isTemplateInstantiation();
1446 if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,
1447 IsTemplateInstantiation))
1451 PerFunction ? diag::warn_unannotated_fallthrough_per_function
1452 : diag::warn_unannotated_fallthrough);
1454 if (!AnnotatedCnt) {
1465 if (!(B->
empty() && isa_and_nonnull<BreakStmt>(Term))) {
1469 TextToInsert +=
"; ";
1470 S.
Diag(L, diag::note_insert_fallthrough_fixit)
1471 << AnnotationSpelling
1474 S.
Diag(L, diag::note_insert_break_fixit)
1479 for (
const auto *F : FM.getFallthroughStmts())
1480 S.
Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement);
1489 case Stmt::ForStmtClass:
1490 case Stmt::WhileStmtClass:
1491 case Stmt::CXXForRangeStmtClass:
1492 case Stmt::ObjCForCollectionStmtClass:
1494 case Stmt::DoStmtClass: {
1498 return Result.
Val.
getInt().getBoolValue();
1515 typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
1524 for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end();
1526 const WeakUseVector &Uses = I->second;
1529 WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
1530 for ( ; UI != UE; ++UI) {
1543 if (UI == Uses.begin()) {
1544 WeakUseVector::const_iterator UI2 = UI;
1545 for (++UI2; UI2 != UE; ++UI2)
1546 if (UI2->isUnsafe())
1550 if (!
isInLoop(Ctx, PM, UI->getUseExpr()))
1553 const WeakObjectProfileTy &Profile = I->first;
1554 if (!Profile.isExactProfile())
1559 Base = Profile.getProperty();
1560 assert(
Base &&
"A profile always has a base or property.");
1562 if (
const VarDecl *BaseVar = dyn_cast<VarDecl>(
Base))
1568 UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
1571 if (UsesByStmt.empty())
1576 llvm::sort(UsesByStmt,
1577 [&
SM](
const StmtUsesPair &LHS,
const StmtUsesPair &RHS) {
1578 return SM.isBeforeInTranslationUnit(LHS.first->getBeginLoc(),
1579 RHS.first->getBeginLoc());
1595 FunctionKind =
Block;
1597 FunctionKind = Lambda;
1599 FunctionKind = Method;
1601 FunctionKind = Function;
1604 for (
const auto &P : UsesByStmt) {
1605 const Stmt *FirstRead = P.first;
1606 const WeakObjectProfileTy &Key = P.second->first;
1607 const WeakUseVector &Uses = P.second->second;
1615 if (Key.isExactProfile())
1616 DiagKind = diag::warn_arc_repeated_use_of_weak;
1618 DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
1630 const NamedDecl *KeyProp = Key.getProperty();
1632 ObjectKind = Variable;
1634 ObjectKind = Property;
1636 ObjectKind = ImplicitProperty;
1640 llvm_unreachable(
"Unexpected weak object kind!");
1645 if (Prop->hasAttr<IBOutletAttr>())
1650 <<
int(ObjectKind) << KeyProp <<
int(FunctionKind)
1654 for (
const auto &Use : Uses) {
1655 if (Use.getUseExpr() == FirstRead)
1657 S.
Diag(Use.getUseExpr()->getBeginLoc(),
1658 diag::note_arc_weak_also_accessed_here)
1659 << Use.getUseExpr()->getSourceRange();
1667typedef std::pair<PartialDiagnosticAt, OptionalNotes>
DelayedDiag;
1668typedef std::list<DelayedDiag>
DiagList;
1670struct SortDiagBySourceLocation {
1672 SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {}
1674 bool operator()(
const DelayedDiag &left,
const DelayedDiag &right) {
1677 return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
1686 typedef SmallVector<UninitUse, 2> UsesVec;
1687 typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
1691 typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
1695 UninitValsDiagReporter(Sema &S) : S(S) {}
1698 MappedType &getUses(
const VarDecl *vd) {
1699 MappedType &
V = uses[vd];
1700 if (!
V.getPointer())
1701 V.setPointer(
new UsesVec());
1705 void handleUseOfUninitVariable(
const VarDecl *vd,
1706 const UninitUse &use)
override {
1707 getUses(vd).getPointer()->push_back(use);
1710 void handleSelfInit(
const VarDecl *vd)
override { getUses(vd).setInt(
true); }
1713 for (
const auto &P : uses) {
1714 const VarDecl *vd = P.first;
1715 const MappedType &
V = P.second;
1717 UsesVec *vec =
V.getPointer();
1718 bool hasSelfInit =
V.getInt();
1720 diagnoseUnitializedVar(vd, hasSelfInit, vec);
1730 static bool hasAlwaysUninitializedUse(
const UsesVec* vec) {
1731 return llvm::any_of(*vec, [](
const UninitUse &U) {
1741 void diagnoseUnitializedVar(
const VarDecl *vd,
bool hasSelfInit,
1746 if (hasSelfInit && hasAlwaysUninitializedUse(vec)) {
1757 llvm::sort(*vec, [](
const UninitUse &a,
const UninitUse &
b) {
1761 return b.isConstRefOrPtrUse();
1768 for (
const auto &U : *vec) {
1777 UninitUse Use = hasSelfInit ? UninitUse(U.
getUser(),
false) : U;
1786class CalledOnceInterProceduralData {
1789 void addDelayedWarning(
const BlockDecl *
Block,
1791 DelayedBlockWarnings[
Block].emplace_back(std::move(
Warning));
1794 void flushWarnings(
const BlockDecl *
Block, Sema &S) {
1796 S.
Diag(Delayed.first, Delayed.second);
1798 discardWarnings(
Block);
1801 void discardWarnings(
const BlockDecl *
Block) {
1802 DelayedBlockWarnings.erase(
Block);
1806 using DelayedDiagnostics = SmallVector<PartialDiagnosticAt, 2>;
1807 llvm::DenseMap<const BlockDecl *, DelayedDiagnostics> DelayedBlockWarnings;
1812 CalledOnceCheckReporter(Sema &S, CalledOnceInterProceduralData &Data)
1813 : S(S), Data(Data) {}
1814 void handleDoubleCall(
const ParmVarDecl *
Parameter,
const Expr *
Call,
1815 const Expr *PrevCall,
bool IsCompletionHandler,
1816 bool Poised)
override {
1817 auto DiagToReport = IsCompletionHandler
1818 ? diag::warn_completion_handler_called_twice
1819 : diag::warn_called_once_gets_called_twice;
1821 S.Diag(PrevCall->
getBeginLoc(), diag::note_called_once_gets_called_twice)
1825 void handleNeverCalled(
const ParmVarDecl *
Parameter,
1826 bool IsCompletionHandler)
override {
1827 auto DiagToReport = IsCompletionHandler
1828 ? diag::warn_completion_handler_never_called
1829 : diag::warn_called_once_never_called;
1830 S.Diag(
Parameter->getBeginLoc(), DiagToReport)
1836 bool IsCalledDirectly,
1837 bool IsCompletionHandler)
override {
1838 auto DiagToReport = IsCompletionHandler
1839 ? diag::warn_completion_handler_never_called_when
1840 : diag::warn_called_once_never_called_when;
1844 << (
unsigned)Reason);
1854 void handleCapturedNeverCalled(
const ParmVarDecl *
Parameter,
1856 bool IsCompletionHandler)
override {
1857 auto DiagToReport = IsCompletionHandler
1858 ? diag::warn_completion_handler_never_called
1859 : diag::warn_called_once_never_called;
1865 handleBlockThatIsGuaranteedToBeCalledOnce(
const BlockDecl *
Block)
override {
1866 Data.flushWarnings(
Block, S);
1869 void handleBlockWithNoGuarantees(
const BlockDecl *
Block)
override {
1870 Data.discardWarnings(
Block);
1875 CalledOnceInterProceduralData &Data;
1878constexpr unsigned CalledOnceWarnings[] = {
1879 diag::warn_called_once_never_called,
1880 diag::warn_called_once_never_called_when,
1881 diag::warn_called_once_gets_called_twice};
1883constexpr unsigned CompletionHandlerWarnings[]{
1884 diag::warn_completion_handler_never_called,
1885 diag::warn_completion_handler_never_called_when,
1886 diag::warn_completion_handler_called_twice};
1891 return llvm::any_of(DiagIDs, [&Diags, At](
unsigned DiagID) {
1898 return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);
1903 return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||
1904 shouldAnalyzeCalledOnceConventions(Diags, At);
1914class ThreadSafetyReporter :
public clang::threadSafety::ThreadSafetyHandler {
1917 SourceLocation FunLocation, FunEndLocation;
1919 const FunctionDecl *CurrentFunction;
1923 if (Verbose && CurrentFunction) {
1925 S.PDiag(diag::note_thread_warning_in_fun)
1926 << CurrentFunction);
1934 if (Verbose && CurrentFunction) {
1936 S.PDiag(diag::note_thread_warning_in_fun)
1937 << CurrentFunction);
1938 ONS.push_back(std::move(FNote));
1946 ONS.push_back(Note1);
1947 ONS.push_back(Note2);
1948 if (Verbose && CurrentFunction) {
1950 S.PDiag(diag::note_thread_warning_in_fun)
1951 << CurrentFunction);
1952 ONS.push_back(std::move(FNote));
1957 OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) {
1960 LocLocked, S.PDiag(diag::note_locked_here) << Kind))
1964 OptionalNotes makeUnlockedHereNote(SourceLocation LocUnlocked,
1968 LocUnlocked, S.PDiag(diag::note_unlocked_here) << Kind))
1972 OptionalNotes makeManagedMismatchNoteForParam(SourceLocation DeclLoc) {
1976 S.PDiag(diag::note_managed_mismatch_here_for_param)))
1981 ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
1982 : S(S), FunLocation(FL), FunEndLocation(FEL),
1985 void setVerbose(
bool b) { Verbose =
b; }
1992 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
1993 for (
const auto &
Diag : Warnings) {
1994 S.Diag(
Diag.first.first,
Diag.first.second);
1995 for (
const auto &
Note :
Diag.second)
2000 void handleUnmatchedUnderlyingMutexes(SourceLocation Loc, SourceLocation DLoc,
2001 Name scopeName, StringRef Kind,
2002 Name expected, Name actual)
override {
2004 S.PDiag(diag::warn_unmatched_underlying_mutexes)
2005 << Kind << scopeName << expected << actual);
2006 Warnings.emplace_back(std::move(
Warning),
2007 makeManagedMismatchNoteForParam(DLoc));
2010 void handleExpectMoreUnderlyingMutexes(SourceLocation Loc,
2011 SourceLocation DLoc, Name scopeName,
2013 Name expected)
override {
2015 Loc, S.PDiag(diag::warn_expect_more_underlying_mutexes)
2016 << Kind << scopeName << expected);
2017 Warnings.emplace_back(std::move(
Warning),
2018 makeManagedMismatchNoteForParam(DLoc));
2021 void handleExpectFewerUnderlyingMutexes(SourceLocation Loc,
2022 SourceLocation DLoc, Name scopeName,
2024 Name actual)
override {
2026 Loc, S.PDiag(diag::warn_expect_fewer_underlying_mutexes)
2027 << Kind << scopeName << actual);
2028 Warnings.emplace_back(std::move(
Warning),
2029 makeManagedMismatchNoteForParam(DLoc));
2032 void handleInvalidLockExp(SourceLocation Loc)
override {
2035 Warnings.emplace_back(std::move(
Warning), getNotes());
2038 void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc,
2039 SourceLocation LocPreviousUnlock)
override {
2043 << Kind << LockName);
2044 Warnings.emplace_back(std::move(
Warning),
2045 makeUnlockedHereNote(LocPreviousUnlock, Kind));
2048 void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
2050 SourceLocation LocLocked,
2051 SourceLocation LocUnlock)
override {
2053 LocUnlock = FunLocation;
2055 LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch)
2056 << Kind << LockName << Received << Expected);
2057 Warnings.emplace_back(std::move(
Warning),
2058 makeLockedHereNote(LocLocked, Kind));
2061 void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked,
2062 SourceLocation LocDoubleLock)
override {
2064 LocDoubleLock = FunLocation;
2066 << Kind << LockName);
2067 Warnings.emplace_back(std::move(
Warning),
2068 makeLockedHereNote(LocLocked, Kind));
2071 void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
2072 SourceLocation LocLocked,
2073 SourceLocation LocEndOfScope,
2075 bool ReentrancyMismatch)
override {
2076 unsigned DiagID = 0;
2079 DiagID = diag::warn_lock_some_predecessors;
2082 DiagID = diag::warn_expecting_lock_held_on_loop;
2085 DiagID = diag::warn_no_unlock;
2088 DiagID = diag::warn_expecting_locked;
2092 LocEndOfScope = FunEndLocation;
2096 << ReentrancyMismatch);
2097 Warnings.emplace_back(std::move(
Warning),
2098 makeLockedHereNote(LocLocked, Kind));
2101 void handleExclusiveAndShared(StringRef Kind, Name LockName,
2102 SourceLocation Loc1,
2103 SourceLocation Loc2)
override {
2105 S.PDiag(diag::warn_lock_exclusive_and_shared)
2106 << Kind << LockName);
2108 << Kind << LockName);
2109 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2113 AccessKind AK, SourceLocation Loc)
override {
2114 unsigned DiagID = 0;
2121 DiagID = diag::warn_variable_requires_any_lock;
2128 DiagID = diag::warn_var_deref_requires_any_lock;
2131 llvm_unreachable(
"Only works for variables");
2136 Warnings.emplace_back(std::move(
Warning), getNotes());
2139 void handleMutexNotHeld(StringRef Kind,
const NamedDecl *D,
2142 Name *PossibleMatch)
override {
2143 unsigned DiagID = 0;
2144 if (PossibleMatch) {
2147 DiagID = diag::warn_variable_requires_lock_precise;
2150 DiagID = diag::warn_var_deref_requires_lock_precise;
2153 DiagID = diag::warn_fun_requires_lock_precise;
2156 DiagID = diag::warn_guarded_pass_by_reference;
2159 DiagID = diag::warn_pt_guarded_pass_by_reference;
2162 DiagID = diag::warn_guarded_return_by_reference;
2165 DiagID = diag::warn_pt_guarded_return_by_reference;
2168 DiagID = diag::warn_guarded_pass_pointer;
2171 DiagID = diag::warn_pt_guarded_pass_pointer;
2174 DiagID = diag::warn_guarded_return_pointer;
2177 DiagID = diag::warn_pt_guarded_return_pointer;
2187 S.PDiag(diag::note_guarded_by_declared_here)
2189 Warnings.emplace_back(std::move(
Warning), getNotes(
Note, VNote));
2191 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2195 DiagID = diag::warn_variable_requires_lock;
2198 DiagID = diag::warn_var_deref_requires_lock;
2201 DiagID = diag::warn_fun_requires_lock;
2204 DiagID = diag::warn_guarded_pass_by_reference;
2207 DiagID = diag::warn_pt_guarded_pass_by_reference;
2210 DiagID = diag::warn_guarded_return_by_reference;
2213 DiagID = diag::warn_pt_guarded_return_by_reference;
2216 DiagID = diag::warn_guarded_pass_pointer;
2219 DiagID = diag::warn_pt_guarded_pass_pointer;
2222 DiagID = diag::warn_guarded_return_pointer;
2225 DiagID = diag::warn_pt_guarded_return_pointer;
2233 S.PDiag(diag::note_guarded_by_declared_here));
2234 Warnings.emplace_back(std::move(
Warning), getNotes(
Note));
2236 Warnings.emplace_back(std::move(
Warning), getNotes());
2240 void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
2241 SourceLocation Loc)
override {
2243 S.PDiag(diag::warn_acquire_requires_negative_cap)
2244 << Kind << LockName << Neg);
2245 Warnings.emplace_back(std::move(
Warning), getNotes());
2248 void handleNegativeNotHeld(
const NamedDecl *D, Name LockName,
2249 SourceLocation Loc)
override {
2251 Loc, S.PDiag(diag::warn_fun_requires_negative_cap) << D << LockName);
2252 Warnings.emplace_back(std::move(
Warning), getNotes());
2255 void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
2256 SourceLocation Loc)
override {
2258 << Kind << FunName << LockName);
2259 Warnings.emplace_back(std::move(
Warning), getNotes());
2262 void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
2263 SourceLocation Loc)
override {
2265 S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
2266 Warnings.emplace_back(std::move(
Warning), getNotes());
2269 void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc)
override {
2271 S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
2272 Warnings.emplace_back(std::move(
Warning), getNotes());
2275 void enterFunction(
const FunctionDecl* FD)
override {
2276 CurrentFunction = FD;
2279 void leaveFunction(
const FunctionDecl* FD)
override {
2280 CurrentFunction =
nullptr;
2301 ConsumedWarningsHandler(Sema &S) : S(S) {}
2304 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
2305 for (
const auto &
Diag : Warnings) {
2306 S.Diag(
Diag.first.first,
Diag.first.second);
2307 for (
const auto &
Note :
Diag.second)
2312 void warnLoopStateMismatch(SourceLocation Loc,
2313 StringRef VariableName)
override {
2320 void warnParamReturnTypestateMismatch(SourceLocation Loc,
2321 StringRef VariableName,
2322 StringRef ExpectedState,
2323 StringRef ObservedState)
override {
2326 diag::warn_param_return_typestate_mismatch) << VariableName <<
2327 ExpectedState << ObservedState);
2332 void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
2333 StringRef ObservedState)
override {
2336 diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
2341 void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
2342 StringRef TypeName)
override {
2344 diag::warn_return_typestate_for_unconsumable_type) << TypeName);
2349 void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
2350 StringRef ObservedState)
override {
2353 diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
2358 void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
2359 SourceLocation Loc)
override {
2362 diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
2367 void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
2368 StringRef State, SourceLocation Loc)
override {
2371 MethodName << VariableName << State);
2387 bool SuggestSuggestions;
2391 std::string listVariableGroupAsString(
2392 const VarDecl *VD,
const ArrayRef<const VarDecl *> &VarGroupForVD)
const {
2393 if (VarGroupForVD.size() <= 1)
2396 std::vector<StringRef> VarNames;
2397 auto PutInQuotes = [](StringRef S) -> std::string {
2398 return "'" + S.str() +
"'";
2401 for (
auto *
V : VarGroupForVD) {
2404 VarNames.push_back(
V->getName());
2406 if (VarNames.size() == 1) {
2407 return PutInQuotes(VarNames[0]);
2409 if (VarNames.size() == 2) {
2410 return PutInQuotes(VarNames[0]) +
" and " + PutInQuotes(VarNames[1]);
2412 assert(VarGroupForVD.size() > 3);
2413 const unsigned N = VarNames.size() -
2415 std::string AllVars =
"";
2417 for (
unsigned I = 0; I < N; ++I)
2418 AllVars.append(PutInQuotes(VarNames[I]) +
", ");
2419 AllVars.append(PutInQuotes(VarNames[N]) +
", and " +
2420 PutInQuotes(VarNames[N + 1]));
2425 UnsafeBufferUsageReporter(Sema &S,
bool SuggestSuggestions)
2426 : S(S), SuggestSuggestions(SuggestSuggestions) {}
2428 void handleUnsafeOperation(
const Stmt *Operation,
bool IsRelatedToDecl,
2429 ASTContext &Ctx)
override {
2432 unsigned MsgParam = 0;
2433 NamedDecl *D =
nullptr;
2434 if (
const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
2435 Loc = ASE->getBase()->getExprLoc();
2436 Range = ASE->getBase()->getSourceRange();
2438 }
else if (
const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
2440 if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
2441 Op == BO_SubAssign) {
2451 }
else if (
const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
2453 if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
2462 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2466 assert(!IsRelatedToDecl &&
"Not implemented yet!");
2468 D = ME->getMemberDecl();
2470 }
else if (
const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) {
2471 QualType destType = ECE->getType();
2472 bool destTypeComplete =
true;
2478 destTypeComplete = D->isCompleteDefinition();
2482 if (destTypeComplete) {
2484 QualType srcType = ECE->getSubExpr()->getType();
2494 if (
const auto *CE = dyn_cast<CXXMemberCallExpr>(
2495 ECE->getSubExpr()->IgnoreParens())) {
2496 D = CE->getMethodDecl();
2507 if (IsRelatedToDecl) {
2508 assert(!SuggestSuggestions &&
2509 "Variables blamed for unsafe buffer usage without suggestions!");
2510 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2513 S.Diag(Loc, diag::warn_unsafe_buffer_operation)
2514 << MsgParam << D <<
Range;
2516 S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam <<
Range;
2518 if (SuggestSuggestions) {
2519 S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled);
2524 void handleUnsafeLibcCall(
const CallExpr *
Call,
unsigned PrintfInfo,
2526 const Expr *UnsafeArg =
nullptr)
override {
2527 S.Diag(
Call->getBeginLoc(), diag::warn_unsafe_buffer_libc_call)
2528 <<
Call->getDirectCallee()
2530 if (PrintfInfo > 0) {
2532 UnsafeArg ? UnsafeArg->getSourceRange() :
Call->getSourceRange();
2533 S.Diag(R.
getBegin(), diag::note_unsafe_buffer_printf_call)
2538 void handleUnsafeOperationInContainer(
const Stmt *Operation,
2539 bool IsRelatedToDecl,
2540 ASTContext &Ctx)
override {
2543 unsigned MsgParam = 0;
2548 Loc = CtorExpr->getLocation();
2550 S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container);
2551 if (IsRelatedToDecl) {
2552 assert(!SuggestSuggestions &&
2553 "Variables blamed for unsafe buffer usage without suggestions!");
2554 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam <<
Range;
2558 void handleUnsafeVariableGroup(
const VarDecl *Variable,
2559 const VariableGroupsManager &VarGrpMgr,
2560 FixItList &&Fixes,
const Decl *D,
2561 const FixitStrategy &VarTargetTypes)
override {
2562 assert(!SuggestSuggestions &&
2563 "Unsafe buffer usage fixits displayed without suggestions!");
2564 S.Diag(
Variable->getLocation(), diag::warn_unsafe_buffer_variable)
2567 if (!Fixes.empty()) {
2569 "Fix-its are generated only for `NamedDecl`s");
2571 bool BriefMsg =
false;
2575 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Variable, &BriefMsg);
2576 unsigned FixItStrategy = 0;
2577 switch (VarTargetTypes.
lookup(Variable)) {
2585 assert(
false &&
"We support only std::span and std::array");
2590 BriefMsg ? diag::note_unsafe_buffer_variable_fixit_together
2591 : diag::note_unsafe_buffer_variable_fixit_group);
2594 FD << listVariableGroupAsString(Variable, VarGroupForVD)
2595 << (VarGroupForVD.size() > 1) << ND;
2596 for (
const auto &F : Fixes) {
2602 if (areDebugNotesRequested())
2603 for (
const DebugNote &
Note: DebugNotesByVar[Variable])
2604 S.Diag(
Note.first, diag::note_safe_buffer_debug_mode) <<
Note.second;
2608 void handleUnsafeUniquePtrArrayAccess(
const DynTypedNode &Node,
2609 bool IsRelatedToDecl,
2610 ASTContext &Ctx)
override {
2614 Loc = Node.
get<Stmt>()->getBeginLoc();
2615 S.Diag(Loc, diag::warn_unsafe_buffer_usage_unique_ptr_array_access)
2619 bool isSafeBufferOptOut(
const SourceLocation &Loc)
const override {
2620 return S.PP.isSafeBufferOptOut(S.getSourceManager(), Loc);
2624 return S.Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container, Loc);
2627 bool ignoreUnsafeBufferInLibcCall(
const SourceLocation &Loc)
const override {
2628 return S.Diags.isIgnored(diag::warn_unsafe_buffer_libc_call, Loc);
2635 getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,
2636 StringRef WSSuffix =
"")
const override {
2637 Preprocessor &PP = S.getPreprocessor();
2638 TokenValue ClangUnsafeBufferUsageTokens[] = {
2647 StringRef MacroName;
2651 if (MacroName.empty())
2652 MacroName =
"[[clang::unsafe_buffer_usage]]";
2653 return MacroName.str() + WSSuffix.str();
2664 enableCheckFallThrough = 1;
2665 enableCheckUnreachable = 0;
2666 enableThreadSafetyAnalysis = 0;
2667 enableConsumedAnalysis = 0;
2688template <
typename... Ts>
2691 return (!D.
isIgnored(Diags, Loc) || ...);
2696 NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),
2697 MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),
2698 NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
2699 NumUninitAnalysisBlockVisits(0),
2700 MaxUninitAnalysisBlockVisitsPerFunction(0) {
2708 using namespace diag;
2714 P.enableCheckUnreachable =
2715 PolicyOverrides.enableCheckUnreachable ||
2716 areAnyEnabled(D, Loc, warn_unreachable, warn_unreachable_break,
2717 warn_unreachable_return, warn_unreachable_loop_increment);
2719 P.enableThreadSafetyAnalysis = PolicyOverrides.enableThreadSafetyAnalysis ||
2722 P.enableConsumedAnalysis = PolicyOverrides.enableConsumedAnalysis ||
2727void sema::AnalysisBasedWarnings::clearOverrides() {
2728 PolicyOverrides.enableCheckUnreachable =
false;
2729 PolicyOverrides.enableConsumedAnalysis =
false;
2730 PolicyOverrides.enableThreadSafetyAnalysis =
false;
2735 S.
Diag(D.Loc, D.PD);
2742 llvm::function_ref<void(
const Decl *)> Callback;
2743 const Module *
const TUModule;
2747 const Module *
const TUModule)
2748 : Callback(Callback), TUModule(TUModule) {
2793namespace clang::lifetimes {
2795class LifetimeSafetyReporterImpl :
public LifetimeSafetyReporter {
2798 LifetimeSafetyReporterImpl(Sema &S) : S(S) {}
2800 void reportUseAfterFree(
const Expr *IssueExpr,
const Expr *UseExpr,
2801 SourceLocation FreeLoc, Confidence
C)
override {
2803 C == Confidence::Definite
2804 ? diag::warn_lifetime_safety_loan_expires_permissive
2805 : diag::warn_lifetime_safety_loan_expires_strict)
2807 S.
Diag(FreeLoc, diag::note_lifetime_safety_destroyed_here);
2808 S.
Diag(UseExpr->
getExprLoc(), diag::note_lifetime_safety_used_here)
2832 bool UnsafeBufferUsageCanEmitSuggestions = S.getLangOpts().CPlusPlus20;
2833 bool UnsafeBufferUsageShouldEmitSuggestions =
2834 UnsafeBufferUsageCanEmitSuggestions &&
2835 DiagOpts.ShowSafeBufferUsageSuggestions;
2836 bool UnsafeBufferUsageShouldSuggestSuggestions =
2837 UnsafeBufferUsageCanEmitSuggestions &&
2838 !DiagOpts.ShowSafeBufferUsageSuggestions;
2839 UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions);
2842 auto CallAnalyzers = [&](
const Decl *Node) ->
void {
2843 if (Node->hasAttr<UnsafeBufferUsageAttr>())
2847 if (!Diags.
isIgnored(diag::warn_unsafe_buffer_operation,
2848 Node->getBeginLoc()) ||
2849 !Diags.
isIgnored(diag::warn_unsafe_buffer_variable,
2850 Node->getBeginLoc()) ||
2851 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2852 Node->getBeginLoc()) ||
2853 !Diags.
isIgnored(diag::warn_unsafe_buffer_libc_call,
2854 Node->getBeginLoc())) {
2856 UnsafeBufferUsageShouldEmitSuggestions);
2865 !Diags.
isIgnored(diag::warn_unsafe_buffer_usage_in_container,
2868 S.getLangOpts().CPlusPlus )) {
2870 .TraverseTranslationUnitDecl(TU);
2896 if (S.hasUncompilableErrorOccurred()) {
2918 bool EnableLifetimeSafetyAnalysis = S.getLangOpts().EnableLifetimeSafety;
2926 if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||
2927 P.enableConsumedAnalysis || EnableLifetimeSafetyAnalysis) {
2942 std::optional<LogicalErrorHandler> LEH;
2943 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->
getBeginLoc())) {
2950 bool analyzed =
false;
2954 for (
const Stmt *S : D.Stmts)
2961 bool AllReachable =
true;
2962 for (
const Stmt *S : D.Stmts) {
2972 AllReachable =
false;
2981 S.Diag(D.Loc, D.PD);
2990 if (P.enableCheckFallThrough) {
2991 const CheckFallThroughDiagnostics &CD =
2996 ? CheckFallThroughDiagnostics::MakeForLambda()
2998 ? CheckFallThroughDiagnostics::MakeForCoroutine(D)
2999 : CheckFallThroughDiagnostics::MakeForFunction(S, D)));
3004 if (P.enableCheckUnreachable) {
3017 if (P.enableThreadSafetyAnalysis) {
3020 threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
3022 Reporter.setIssueBetaWarnings(
true);
3024 Reporter.setVerbose(
true);
3027 &S.ThreadSafetyDeclCache);
3028 Reporter.emitDiagnostics();
3032 if (P.enableConsumedAnalysis) {
3033 consumed::ConsumedWarningsHandler WarningHandler(S);
3044 UninitValsDiagReporter reporter(S);
3051 ++NumUninitAnalysisFunctions;
3054 MaxUninitAnalysisVariablesPerFunction =
3055 std::max(MaxUninitAnalysisVariablesPerFunction,
3057 MaxUninitAnalysisBlockVisitsPerFunction =
3058 std::max(MaxUninitAnalysisBlockVisitsPerFunction,
3066 if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {
3068 lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);
3073 if (S.getLangOpts().ObjC && !S.getLangOpts().CPlusPlus &&
3074 shouldAnalyzeCalledOnceParameters(Diags, D->
getBeginLoc())) {
3076 CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);
3079 shouldAnalyzeCalledOnceConventions(Diags, D->
getBeginLoc()));
3083 bool FallThroughDiagFull =
3085 bool FallThroughDiagPerFunction = !Diags.
isIgnored(
3086 diag::warn_unannotated_fallthrough_per_function, D->
getBeginLoc());
3087 if (FallThroughDiagFull || FallThroughDiagPerFunction ||
3092 if (S.getLangOpts().ObjCWeak &&
3098 if (!Diags.
isIgnored(diag::warn_infinite_recursive_function,
3100 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
3107 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
3113 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->
getBeginLoc())) {
3122 ++NumFunctionsAnalyzed;
3126 NumCFGBlocks += cfg->getNumBlockIDs();
3127 MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
3128 cfg->getNumBlockIDs());
3130 ++NumFunctionsWithBadCFGs;
3136 llvm::errs() <<
"\n*** Analysis Based Warnings Stats:\n";
3138 unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
3139 unsigned AvgCFGBlocksPerFunction =
3140 !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
3141 llvm::errs() << NumFunctionsAnalyzed <<
" functions analyzed ("
3142 << NumFunctionsWithBadCFGs <<
" w/o CFGs).\n"
3143 <<
" " << NumCFGBlocks <<
" CFG blocks built.\n"
3144 <<
" " << AvgCFGBlocksPerFunction
3145 <<
" average CFG blocks per function.\n"
3146 <<
" " << MaxCFGBlocksPerFunction
3147 <<
" max CFG blocks per function.\n";
3149 unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
3150 : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
3151 unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
3152 : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
3153 llvm::errs() << NumUninitAnalysisFunctions
3154 <<
" functions analyzed for uninitialiazed variables\n"
3155 <<
" " << NumUninitAnalysisVariables <<
" variables analyzed.\n"
3156 <<
" " << AvgUninitVariablesPerFunction
3157 <<
" average variables per function.\n"
3158 <<
" " << MaxUninitAnalysisVariablesPerFunction
3159 <<
" max variables per function.\n"
3160 <<
" " << NumUninitAnalysisBlockVisits <<
" block visits.\n"
3161 <<
" " << AvgUninitBlockVisitsPerFunction
3162 <<
" average block visits per function.\n"
3163 <<
" " << MaxUninitAnalysisBlockVisitsPerFunction
3164 <<
" max block visits per function.\n";
static void visitReachableThrows(CFG *BodyCFG, llvm::function_ref< void(const CXXThrowExpr *, CFGBlock &)> Visit)
static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD)
static bool isReferenceToNoReturn(const Expr *E)
Checks if the given expression is a reference to a function with 'noreturn' attribute.
static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM, const Stmt *S)
static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC)
CheckFallThrough - Check that we don't fall off the end of a Statement that should return a value.
static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, QualType BlockType, const CheckFallThroughDiagnostics &CD, AnalysisDeclContext &AC)
CheckFallThroughForBody - Check that we don't fall off the end of a function that should return a val...
static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope)
static void diagnoseRepeatedUseOfWeak(Sema &S, const sema::FunctionScopeInfo *CurFn, const Decl *D, const ParentMap &PM)
static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, const FunctionDecl *FD)
static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, bool PerFunction)
static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, AnalysisDeclContext &AC)
static void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then, const Stmt *Else, bool CondVal, FixItHint &Fixit1, FixItHint &Fixit2)
Create a fixit to remove an if-like statement, on the assumption that its condition is CondVal.
static StringRef getFallthroughAttrSpelling(Preprocessor &PP, SourceLocation Loc)
static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, const UninitUse &Use, bool alwaysReportSelfInit=false)
DiagnoseUninitializedUse – Helper function for diagnosing uses of an uninitialized variable.
static bool areAnyEnabled(DiagnosticsEngine &D, SourceLocation Loc, Ts... Diags)
static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block)
static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock, CFG *Body)
Determine whether an exception thrown by E, unwinding from ThrowBlock, can reach ExitBlock.
static bool areAllValuesNoReturn(const VarDecl *VD, const CFGBlock &VarBlk, AnalysisDeclContext &AC)
static bool isNoexcept(const FunctionDecl *FD)
static bool DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD, const UninitUse &Use)
Diagnose uninitialized const reference usages.
static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, bool IsCapturedByBlock)
DiagUninitUse – Helper function to produce a diagnostic for an uninitialized use of a variable.
static bool DiagnoseUninitializedConstPtrUse(Sema &S, const VarDecl *VD, const UninitUse &Use)
Diagnose uninitialized const pointer usages.
static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC)
CheckUnreachable - Check for unreachable code.
@ NeverFallThroughOrReturn
static bool isInitializedWithNoReturn(const VarDecl *VD)
Checks if the given variable, which is assumed to be a function pointer, is initialized with a functi...
static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, const Stmt *Body, AnalysisDeclContext &AC)
static bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg)
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
Defines the Diagnostic-related interfaces.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
static bool EvaluateAsInt(const Expr *E, Expr::EvalResult &ExprResult, const ASTContext &Ctx, Expr::SideEffectsKind AllowSideEffects, EvalInfo &Info)
static std::pair< const Stmt *, const CFGBlock * > getLastStmt(const ExplodedNode *Node)
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
static void emitDiagnostics(BoundNodes &Match, const Decl *D, BugReporter &BR, AnalysisManager &AM, const ObjCAutoreleaseWriteChecker *Checker)
llvm::DenseMap< Stmt *, Stmt * > MapTy
Defines the clang::Preprocessor interface.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Defines the Objective-C statement AST node classes.
C Language Family Type Representation.
@ Open
The standard open() call: int open(const char *path, int oflag, ...);.
static bool ignoreUnsafeBufferInContainer(const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
TextDiagnosticBuffer::DiagList DiagList
__device__ __2f16 float __ockl_bool s
CallableVisitor(llvm::function_ref< void(const Decl *)> Callback, const Module *const TUModule)
bool VisitObjCMethodDecl(ObjCMethodDecl *Node) override
bool TraverseDecl(Decl *Node) override
bool VisitBlockDecl(BlockDecl *Node) override
bool VisitFunctionDecl(FunctionDecl *Node) override
bool VisitLambdaExpr(LambdaExpr *Node) override
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
AnalysisDeclContext contains the context data for the function, method or block under analysis.
void registerForcedBlockExpression(const Stmt *stmt)
const CFGBlock * getBlockForRegisteredExpression(const Stmt *stmt)
ParentMap & getParentMap()
const Decl * getDecl() const
bool getAddEHEdges() const
CFGReverseBlockReachabilityAnalysis * getCFGReachablityAnalysis()
ASTContext & getASTContext() const
CFG::BuildOptions & getCFGBuildOptions()
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isLogicalOp(Opcode Opc)
SourceLocation getBeginLoc() const LLVM_READONLY
SourceLocation getOperatorLoc() const
SourceLocation getExprLoc() const
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
BinaryOperatorKind Opcode
Represents a block literal declaration, which is like an unnamed FunctionDecl.
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
SourceLocation getBeginLoc() const LLVM_READONLY
unsigned IgnoreDefaultsWithCoveredEnums
Represents a single basic block in a source-level CFG.
filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const
reverse_iterator rbegin()
bool hasNoReturnElement() const
ElementList::const_reverse_iterator const_reverse_iterator
FilteredCFGBlockIterator< const_pred_iterator, true > filtered_pred_iterator
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
pred_iterator pred_begin()
unsigned getBlockID() const
unsigned succ_size() const
CFGCallback defines methods that should be called when a logical operator error is found when buildin...
Represents a top-level expression in a basic block.
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type.
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
bool isReachable(const CFGBlock *Src, const CFGBlock *Dst)
Returns true if the block 'Dst' can be reached from block 'Src'.
const Stmt * getStmt() const
bool PruneTriviallyFalseEdges
bool AddCXXDefaultInitExprInCtors
BuildOptions & setAllAlwaysAdd()
BuildOptions & setAlwaysAdd(Stmt::StmtClass stmtClass, bool val=true)
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Represents a call to a member function that may be written either with member call syntax (e....
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
A C++ throw-expression (C++ [except.throw]).
const Expr * getSubExpr() const
SourceLocation getThrowLoc() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
ExprIterator arg_iterator
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getBegin() const
ConditionalOperator - The ?
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
Expr * getCond() const
getCond - Return the expression representing the condition for the ?
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
ConstEvaluatedExprVisitor - This class visits 'const Expr *'s.
void enqueueBlock(const CFGBlock *Block)
const CFGBlock * dequeue()
bool isFunctionOrMethod() const
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
SourceLocation getEndLoc() const LLVM_READONLY
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Module * getOwningModule() const
Get the module that owns this declaration (for visibility purposes).
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
SourceLocation getLocation() const
DeclContext * getDeclContext()
SourceLocation getBeginLoc() const LLVM_READONLY
DeclContext * getLexicalDeclContext()
getLexicalDeclContext - The declaration context where this Decl was lexically declared (LexicalDC).
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
OverloadedOperatorKind getCXXOverloadedOperator() const
If this name is the name of an overloadable operator in C++ (e.g., operator+), retrieve the kind of o...
SourceLocation getBeginLoc() const LLVM_READONLY
TypeSourceInfo * getTypeSourceInfo() const
Options for controlling the compiler diagnostics engine.
Concrete class used by the front-end to report problems and issues.
bool isLastDiagnosticIgnored() const
Determine whether the previous diagnostic was ignored.
bool getIgnoreAllWarnings() const
DiagnosticOptions & getDiagnosticOptions() const
Retrieve the diagnostic options.
bool isIgnored(unsigned DiagID, SourceLocation Loc) const
Determine whether the diagnostic is known to be ignored.
bool getSuppressSystemWarnings() const
const T * get() const
Retrieve the stored node as type T.
SourceRange getSourceRange(bool IncludeQualifier=false) const
For nodes which represent textual entities in the source code, return their SourceRange.
virtual bool TraverseDecl(MaybeConst< Decl > *D)
bool ShouldVisitTemplateInstantiations
bool ShouldVisitImplicitCode
void VisitDeclRefExpr(PTR(DeclRefExpr) E)
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
static FixItHint CreateRemoval(CharSourceRange RemoveRange)
Create a code modification hint that removes the given source range.
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
Kind lookup(const VarDecl *VD) const
Represents a function declaration or definition.
FunctionDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
bool doesThisDeclarationHaveABody() const
Returns whether this specific declaration of the function has a body.
SourceRange getExceptionSpecSourceRange() const
Attempt to compute an informative source range covering the function exception specification,...
@ TK_MemberSpecialization
TemplatedKind getTemplatedKind() const
What kind of templated function this is.
bool isCPUDispatchMultiVersion() const
True if this function is a multiversioned dispatch function as a part of the cpu_specific/cpu_dispatc...
Represents a prototype with parameter type info, e.g.
FunctionType - C99 6.7.5.3 - Function Declarators.
IfStmt - This represents an if/then/else.
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
CXXMethodDecl * getCallOperator() const
Retrieve the function call operator associated with this lambda expression.
Describes a module or submodule.
This represents a decl that may have a name.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
@ Type
A type, stored as a Type*.
ObjCMethodDecl - Represents an instance or class method declaration.
bool hasBody() const override
Determine whether this method has a body.
Represents one property declaration in an Objective-C interface.
Stmt * getParent(Stmt *) const
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
const LangOptions & getLangOpts() const
StringRef getLastMacroWithSpelling(SourceLocation Loc, ArrayRef< TokenValue > Tokens) const
Return the name of the macro defined before Loc that has spelling Tokens.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
bool isConstant(const ASTContext &Ctx) const
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
QualType getCanonicalType() const
bool isConstQualified() const
Determine whether this type is const-qualified.
bool hasObjCLifetime() const
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
Sema - This implements semantic analysis and AST building for C.
Preprocessor & getPreprocessor() const
DiagnosticsEngine & getDiagnostics() const
ASTContext & getASTContext() const
std::string getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const
Get a string to suggest for zero-initialization of a type.
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Calls Lexer::getLocForEndOfToken()
const LangOptions & getLangOpts() const
SourceManager & getSourceManager() const
bool handlerCanCatch(QualType HandlerType, QualType ExceptionType)
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
bool isInMainFile(SourceLocation Loc) const
Returns whether the PresumedLoc for a given SourceLocation is in the main file.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Stmt - This represents one statement.
SourceLocation getEndLoc() const LLVM_READONLY
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SourceLocation getBeginLoc() const LLVM_READONLY
Stores token information for comparing actual tokens with predefined values.
The top declaration context.
QualType getType() const
Return the type wrapped by this type source info.
bool isBlockPointerType() const
bool isPointerType() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
const T * castAs() const
Member-template castAs<specific type>.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
TagDecl * getAsTagDecl() const
Retrieves the TagDecl that this type refers to, either because the type is a TagType or because it is...
const T * getAs() const
Member-template getAs<specific type>'.
Expr * getSubExpr() const
A use of a variable, which might be uninitialized.
const Expr * getUser() const
Get the expression containing the uninitialized use.
SmallVectorImpl< Branch >::const_iterator branch_iterator
branch_iterator branch_end() const
bool isConstPtrUse() const
bool isConstRefOrPtrUse() const
bool isConstRefUse() const
branch_iterator branch_begin() const
Branches which inevitably result in the variable being used uninitialized.
@ Always
The use is always uninitialized.
@ AfterDecl
The use is uninitialized the first time it is reached after we reach the variable's declaration.
@ Maybe
The use might be uninitialized.
@ AfterCall
The use is uninitialized the first time it is reached after the function is called.
@ Sometimes
The use is uninitialized whenever a certain branch is taken.
Kind getKind() const
Get the kind of uninitialized use.
The interface that lets the caller handle unsafe buffer usage analysis results by overriding this cla...
Represents a variable declaration or definition.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
VarDecl * getDefinition(ASTContext &)
Get the real (not just tentative) definition for this declaration.
const Expr * getInit() const
virtual VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm=nullptr) const =0
Returns the set of variables (including Var) that need to be fixed together in one step.
A class that handles the analysis of uniqueness violations.
void IssueWarnings(Policy P, FunctionScopeInfo *fscope, const Decl *D, QualType BlockType)
AnalysisBasedWarnings(Sema &s)
Policy getPolicyInEffectAt(SourceLocation Loc)
Represents a simple identification of a weak object.
Retains information about a function, method, or block that is currently being parsed.
bool HasFallthroughStmt
Whether there is a fallthrough statement in this function.
SmallVector< WeakUseTy, 4 > WeakUseVector
Used to collect uses of a particular weak object in a function body.
SmallVector< PossiblyUnreachableDiag, 4 > PossiblyUnreachableDiags
A list of PartialDiagnostics created but delayed within the current function scope.
llvm::SmallDenseMap< WeakObjectProfileTy, WeakUseVector, 8, WeakObjectProfileTy::DenseMapInfo > WeakObjectUseMap
Used to collect all uses of weak objects in a function body.
const WeakObjectUseMap & getWeakObjectUses() const
InterProceduralData aims to be a storage of whatever data should be passed between analyses of differ...
CalledOnceInterProceduralData CalledOnceData
std::list< DelayedDiag > DiagList
std::pair< PartialDiagnosticAt, OptionalNotes > DelayedDiag
SmallVector< PartialDiagnosticAt, 1 > OptionalNotes
uint32_t Variable
Boolean variables are represented as positive integers.
bool LE(InterpState &S, CodePtr OpPC)
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter)
The main entry point for the analysis.
void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP, Callback &CB)
unsigned ScanReachableFromBlock(const CFGBlock *Start, llvm::BitVector &Reachable)
ScanReachableFromBlock - Mark all blocks reachable from Start.
UnreachableKind
Classifications of unreachable code.
LockKind getLockKindFromAccessKind(AccessKind AK)
Helper function that returns a LockKind required for the given level of access.
LockErrorKind
This enum distinguishes between different situations where we warn due to inconsistent locking.
@ LEK_NotLockedAtEndOfFunction
Expecting a capability to be held at the end of function.
@ LEK_LockedSomePredecessors
A capability is locked in some but not all predecessors of a CFGBlock.
@ LEK_LockedAtEndOfFunction
A capability is still locked at the end of a function.
@ LEK_LockedSomeLoopIterations
A capability is locked for some but not all loop iterations.
AccessKind
This enum distinguishes between different ways to access (read or write) a variable.
LockKind
This enum distinguishes between different kinds of lock actions.
void runThreadSafetyAnalysis(AnalysisDeclContext &AC, ThreadSafetyHandler &Handler, BeforeSet **Bset)
Check a function's CFG for thread-safety violations.
ProtectedOperationKind
This enum distinguishes between different kinds of operations that may need to be protected by locks.
@ POK_PtPassByRef
Passing a pt-guarded variable by reference.
@ POK_PassPointer
Passing pointer to a guarded variable.
@ POK_VarDereference
Dereferencing a variable (e.g. p in *p = 5;)
@ POK_PassByRef
Passing a guarded variable by reference.
@ POK_ReturnByRef
Returning a guarded variable by reference.
@ POK_PtPassPointer
Passing a pt-guarded pointer.
@ POK_PtReturnPointer
Returning a pt-guarded pointer.
@ POK_VarAccess
Reading or writing a variable (e.g. x in x = 5;)
@ POK_FunctionCall
Making a function call (e.g. fool())
@ POK_ReturnPointer
Returning pointer to a guarded variable.
@ POK_PtReturnByRef
Returning a pt-guarded variable by reference.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
bool isTemplateInstantiation(TemplateSpecializationKind Kind)
Determine whether this template specialization kind refers to an instantiation of an entity (as oppos...
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
bool hasSpecificAttr(const Container &container)
@ If
'if' clause, allowed on all the Compute Constructs, Data Constructs, Executable Constructs,...
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ Parameter
The parameter type of a method or function.
void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats)
void checkCalledOnceParameters(AnalysisDeclContext &AC, CalledOnceCheckHandler &Handler, bool CheckConventionalParameters)
Check given CFG for 'called once' parameter violations.
std::pair< SourceLocation, PartialDiagnostic > PartialDiagnosticAt
A partial diagnostic along with the source location where this diagnostic occurs.
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
A worklist implementation for backward dataflow analysis.
void enqueuePredecessors(const CFGBlock *Block)
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.
unsigned NumVariablesAnalyzed