40 #include "llvm/ADT/ArrayRef.h"
41 #include "llvm/ADT/BitVector.h"
42 #include "llvm/ADT/FoldingSet.h"
43 #include "llvm/ADT/ImmutableMap.h"
44 #include "llvm/ADT/MapVector.h"
45 #include "llvm/ADT/PostOrderIterator.h"
46 #include "llvm/ADT/SmallString.h"
47 #include "llvm/ADT/SmallVector.h"
48 #include "llvm/ADT/StringRef.h"
49 #include "llvm/Support/Casting.h"
55 using namespace clang;
65 UnreachableCodeHandler(
Sema &s) :
S(s) {}
72 unsigned diag = diag::warn_unreachable;
75 diag = diag::warn_unreachable_break;
78 diag = diag::warn_unreachable_return;
81 diag = diag::warn_unreachable_loop_increment;
87 S.
Diag(L, diag) << R1 << R2;
94 S.
Diag(Open, diag::note_unreachable_silence)
115 UnreachableCodeHandler UC(S);
127 static bool HasMacroID(
const Expr *
E) {
132 for (
const Stmt *SubStmt : E->children())
133 if (
const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt))
134 if (HasMacroID(SubExpr))
140 void compareAlwaysTrue(
const BinaryOperator *B,
bool isAlwaysTrue)
override {
146 << DiagRange << isAlwaysTrue;
150 bool isAlwaysTrue)
override {
156 << DiagRange << isAlwaysTrue;
170 for (
const auto &B : Block) {
184 isa<TemplateSpecializationType>(NNS->getAsType())) {
220 while (!Stack.empty()) {
241 unsigned next_ID = (*I)->getBlockID();
242 if (States[next_ID] < CurState) {
243 States[next_ID] = CurState;
273 S.
Diag(Body->getLocStart(), diag::warn_infinite_recursive_function);
312 for (
const auto *B : *cfg) {
313 if (!live[B->getBlockID()]) {
314 if (B->pred_begin() == B->pred_end()) {
315 if (B->getTerminator() && isa<CXXTryStmt>(B->getTerminator()))
327 bool HasLiveReturn =
false;
328 bool HasFakeEdge =
false;
329 bool HasPlainEdge =
false;
330 bool HasAbnormalEdge =
false;
338 I = cfg->getExit().filtered_pred_start_end(FO);
I.hasMore(); ++
I) {
347 HasAbnormalEdge =
true;
356 for ( ; ri != re ; ++ri)
363 HasAbnormalEdge =
true;
373 if (isa<ReturnStmt>(S)) {
374 HasLiveReturn =
true;
377 if (isa<ObjCAtThrowStmt>(S)) {
381 if (isa<CXXThrowExpr>(S)) {
385 if (isa<MSAsmStmt>(S)) {
388 HasLiveReturn =
true;
391 if (isa<CXXTryStmt>(S)) {
392 HasAbnormalEdge =
true;
397 HasAbnormalEdge =
true;
408 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
418 struct CheckFallThroughDiagnostics {
419 unsigned diag_MaybeFallThrough_HasNoReturn;
420 unsigned diag_MaybeFallThrough_ReturnsNonVoid;
421 unsigned diag_AlwaysFallThrough_HasNoReturn;
422 unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
423 unsigned diag_NeverFallThroughOrReturn;
424 enum { Function, Block, Lambda } funMode;
427 static CheckFallThroughDiagnostics MakeForFunction(
const Decl *Func) {
428 CheckFallThroughDiagnostics D;
430 D.diag_MaybeFallThrough_HasNoReturn =
431 diag::warn_falloff_noreturn_function;
432 D.diag_MaybeFallThrough_ReturnsNonVoid =
433 diag::warn_maybe_falloff_nonvoid_function;
434 D.diag_AlwaysFallThrough_HasNoReturn =
435 diag::warn_falloff_noreturn_function;
436 D.diag_AlwaysFallThrough_ReturnsNonVoid =
437 diag::warn_falloff_nonvoid_function;
441 bool isVirtualMethod =
false;
442 if (
const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func))
443 isVirtualMethod = Method->isVirtual();
447 if (
const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func))
448 isTemplateInstantiation = Function->isTemplateInstantiation();
450 if (!isVirtualMethod && !isTemplateInstantiation)
451 D.diag_NeverFallThroughOrReturn =
452 diag::warn_suggest_noreturn_function;
454 D.diag_NeverFallThroughOrReturn = 0;
456 D.funMode = Function;
460 static CheckFallThroughDiagnostics MakeForBlock() {
461 CheckFallThroughDiagnostics D;
462 D.diag_MaybeFallThrough_HasNoReturn =
463 diag::err_noreturn_block_has_return_expr;
464 D.diag_MaybeFallThrough_ReturnsNonVoid =
465 diag::err_maybe_falloff_nonvoid_block;
466 D.diag_AlwaysFallThrough_HasNoReturn =
467 diag::err_noreturn_block_has_return_expr;
468 D.diag_AlwaysFallThrough_ReturnsNonVoid =
469 diag::err_falloff_nonvoid_block;
470 D.diag_NeverFallThroughOrReturn = 0;
475 static CheckFallThroughDiagnostics MakeForLambda() {
476 CheckFallThroughDiagnostics D;
477 D.diag_MaybeFallThrough_HasNoReturn =
478 diag::err_noreturn_lambda_has_return_expr;
479 D.diag_MaybeFallThrough_ReturnsNonVoid =
480 diag::warn_maybe_falloff_nonvoid_lambda;
481 D.diag_AlwaysFallThrough_HasNoReturn =
482 diag::err_noreturn_lambda_has_return_expr;
483 D.diag_AlwaysFallThrough_ReturnsNonVoid =
484 diag::warn_falloff_nonvoid_lambda;
485 D.diag_NeverFallThroughOrReturn = 0;
491 bool HasNoReturn)
const {
492 if (funMode == Function) {
493 return (ReturnsVoid ||
494 D.
isIgnored(diag::warn_maybe_falloff_nonvoid_function,
497 D.
isIgnored(diag::warn_noreturn_function_has_return_expr,
500 D.
isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));
504 return ReturnsVoid && !HasNoReturn;
516 const CheckFallThroughDiagnostics& CD,
519 bool ReturnsVoid =
false;
520 bool HasNoReturn =
false;
522 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
523 ReturnsVoid = FD->getReturnType()->isVoidType();
524 HasNoReturn = FD->isNoReturn();
526 else if (
const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
527 ReturnsVoid = MD->getReturnType()->isVoidType();
528 HasNoReturn = MD->hasAttr<NoReturnAttr>();
530 else if (isa<BlockDecl>(D)) {
534 if (FT->getReturnType()->isVoidType())
536 if (FT->getNoReturnAttr())
544 if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
547 SourceLocation LBrace = Body->getLocStart(), RBrace = Body->getLocEnd();
555 S.
Diag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);
556 else if (!ReturnsVoid)
557 S.
Diag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);
561 S.
Diag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);
562 else if (!ReturnsVoid)
563 S.
Diag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
566 if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
567 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
568 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
569 }
else if (
const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
570 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
572 S.
Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
597 : Inherited(Context), FoundReference(
false), Needle(Needle) {}
599 void VisitExpr(
const Expr *E) {
604 Inherited::VisitExpr(E);
609 FoundReference =
true;
611 Inherited::VisitDeclRefExpr(E);
614 bool doesContainReference()
const {
return FoundReference; }
622 S.
Diag(VD->
getLocation(), diag::note_block_var_fixit_add_initialization)
643 S.
Diag(Loc, diag::note_var_fixit_add_initialization) << VD->
getDeclName()
651 const Stmt *Else,
bool CondVal,
657 Then->getLocStart()));
668 Else->getLocStart()));
677 bool IsCapturedByBlock) {
678 bool Diagnosed =
false;
682 S.
Diag(Use.
getUser()->getLocStart(), diag::warn_uninit_var)
684 << Use.
getUser()->getSourceRange();
694 S.
Diag(Use.
getUser()->getLocStart(), diag::note_uninit_var_use)
695 << IsCapturedByBlock << Use.
getUser()->getSourceRange();
711 const Stmt *Term =
I->Terminator;
721 int RemoveDiagKind = -1;
722 const char *FixitStr =
723 S.
getLangOpts().CPlusPlus ? (
I->Output ?
"true" :
"false")
724 : (
I->Output ?
"1" :
"0");
727 switch (Term ? Term->getStmtClass() : Stmt::DeclStmtClass) {
734 case Stmt::IfStmtClass: {
735 const IfStmt *IS = cast<IfStmt>(Term);
738 Range = IS->
getCond()->getSourceRange();
741 I->Output, Fixit1, Fixit2);
744 case Stmt::ConditionalOperatorClass: {
748 Range = CO->
getCond()->getSourceRange();
751 I->Output, Fixit1, Fixit2);
754 case Stmt::BinaryOperatorClass: {
760 Range = BO->
getLHS()->getSourceRange();
774 case Stmt::WhileStmtClass:
777 Range = cast<WhileStmt>(Term)->getCond()->getSourceRange();
781 case Stmt::ForStmtClass:
784 Range = cast<ForStmt>(Term)->getCond()->getSourceRange();
791 case Stmt::CXXForRangeStmtClass:
792 if (
I->Output == 1) {
800 Range = cast<CXXForRangeStmt>(Term)->getRangeInit()->getSourceRange();
804 case Stmt::DoStmtClass:
807 Range = cast<DoStmt>(Term)->getCond()->getSourceRange();
813 case Stmt::CaseStmtClass:
816 Range = cast<CaseStmt>(Term)->getLHS()->getSourceRange();
818 case Stmt::DefaultStmtClass:
821 Range = cast<DefaultStmt>(Term)->getDefaultLoc();
825 S.
Diag(Range.
getBegin(), diag::warn_sometimes_uninit_var)
826 << VD->
getDeclName() << IsCapturedByBlock << DiagKind
827 << Str <<
I->Output << Range;
828 S.
Diag(User->getLocStart(), diag::note_uninit_var_use)
829 << IsCapturedByBlock << User->getSourceRange();
830 if (RemoveDiagKind != -1)
832 << RemoveDiagKind << Str <<
I->Output << Fixit1 << Fixit2;
838 S.
Diag(Use.
getUser()->getLocStart(), diag::warn_maybe_uninit_var)
840 << Use.
getUser()->getSourceRange();
850 bool alwaysReportSelfInit =
false) {
864 if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts())
867 ContainsReference CR(S.
Context, DRE);
868 CR.Visit(Initializer);
869 if (CR.doesContainReference()) {
870 S.
Diag(DRE->getLocStart(),
871 diag::warn_uninit_self_reference_in_init)
882 diag::warn_uninit_byref_blockvar_captured_by_block)
901 FallthroughMapper(
Sema &
S)
902 : FoundSwitchStatements(
false),
906 bool foundSwitchStatements()
const {
return FoundSwitchStatements; }
909 bool Found = FallthroughStmts.erase(Stmt);
914 typedef llvm::SmallPtrSet<const AttributedStmt*, 8> AttrStmts;
916 const AttrStmts &getFallthroughStmts()
const {
917 return FallthroughStmts;
920 void fillReachableBlocks(
CFG *Cfg) {
921 assert(ReachableBlocks.empty() &&
"ReachableBlocks already filled");
922 std::deque<const CFGBlock *> BlockQueue;
924 ReachableBlocks.insert(&Cfg->
getEntry());
925 BlockQueue.push_back(&Cfg->
getEntry());
930 for (
const auto *B : *Cfg) {
931 const Stmt *L = B->getLabel();
932 if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B).second)
933 BlockQueue.push_back(B);
936 while (!BlockQueue.empty()) {
938 BlockQueue.pop_front();
942 if (*
I && ReachableBlocks.insert(*I).second)
943 BlockQueue.push_back(*
I);
948 bool checkFallThroughIntoBlock(
const CFGBlock &B,
int &AnnotatedCnt) {
949 assert(!ReachableBlocks.empty() &&
"ReachableBlocks empty");
951 int UnannotatedCnt = 0;
955 while (!BlockQueue.empty()) {
957 BlockQueue.pop_front();
961 if (Term && isa<SwitchStmt>(Term))
972 if (!ReachableBlocks.count(P)) {
975 ElemIt != ElemEnd; ++ElemIt) {
977 if (
const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
978 S.
Diag(AS->getLocStart(),
979 diag::warn_fallthrough_attr_unreachable);
980 markFallthroughVisited(AS);
1000 markFallthroughVisited(AS);
1008 std::back_inserter(BlockQueue));
1014 return !!UnannotatedCnt;
1018 bool shouldWalkTypesOfTypeLocs()
const {
return false; }
1021 if (asFallThroughAttr(S))
1022 FallthroughStmts.insert(S);
1027 FoundSwitchStatements =
true;
1033 bool TraverseDecl(
Decl *D) {
return true; }
1036 bool TraverseLambdaBody(
LambdaExpr *LE) {
return true; }
1041 if (
const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
1042 if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs()))
1053 ElemIt != ElemEnd; ++ElemIt) {
1055 return CS->getStmt();
1067 bool FoundSwitchStatements;
1068 AttrStmts FallthroughStmts;
1070 llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
1088 FallthroughMapper FM(S);
1089 FM.TraverseStmt(AC.
getBody());
1091 if (!FM.foundSwitchStatements())
1094 if (PerFunction && FM.getFallthroughStmts().empty())
1102 FM.fillReachableBlocks(Cfg);
1104 for (
const CFGBlock *B : llvm::reverse(*Cfg)) {
1107 if (!Label || !isa<SwitchCase>(Label))
1112 if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt))
1115 S.
Diag(Label->getLocStart(),
1116 PerFunction ? diag::warn_unannotated_fallthrough_per_function
1117 : diag::warn_unannotated_fallthrough);
1119 if (!AnnotatedCnt) {
1130 if (!(B->
empty() && Term && isa<BreakStmt>(Term))) {
1135 tok::r_square, tok::r_square
1137 StringRef AnnotationSpelling =
"[[clang::fallthrough]]";
1139 if (!MacroName.empty())
1140 AnnotationSpelling = MacroName;
1142 TextToInsert +=
"; ";
1143 S.
Diag(L, diag::note_insert_fallthrough_fixit) <<
1144 AnnotationSpelling <<
1148 S.
Diag(L, diag::note_insert_break_fixit) <<
1153 for (
const auto *F : FM.getFallthroughStmts())
1154 S.
Diag(F->getLocStart(), diag::warn_fallthrough_attr_invalid_placement);
1162 switch (S->getStmtClass()) {
1163 case Stmt::ForStmtClass:
1164 case Stmt::WhileStmtClass:
1165 case Stmt::CXXForRangeStmtClass:
1166 case Stmt::ObjCForCollectionStmtClass:
1168 case Stmt::DoStmtClass: {
1169 const Expr *Cond = cast<DoStmt>(
S)->getCond();
1173 return Val.getBoolValue();
1190 typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
1199 for (WeakObjectUseMap::const_iterator
I = WeakMap.begin(), E = WeakMap.end();
1201 const WeakUseVector &Uses =
I->second;
1204 WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
1205 for ( ; UI != UE; ++UI) {
1218 if (UI == Uses.begin()) {
1219 WeakUseVector::const_iterator UI2 = UI;
1220 for (++UI2; UI2 != UE; ++UI2)
1221 if (UI2->isUnsafe())
1225 if (!
isInLoop(Ctx, PM, UI->getUseExpr()))
1228 const WeakObjectProfileTy &
Profile =
I->first;
1229 if (!Profile.isExactProfile())
1234 Base = Profile.getProperty();
1235 assert(Base &&
"A profile always has a base or property.");
1237 if (
const VarDecl *BaseVar = dyn_cast<VarDecl>(Base))
1238 if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(Base))
1243 UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(),
I));
1246 if (UsesByStmt.empty())
1251 std::sort(UsesByStmt.begin(), UsesByStmt.end(),
1252 [&
SM](
const StmtUsesPair &LHS,
const StmtUsesPair &RHS) {
1254 RHS.first->getLocStart());
1269 if (isa<sema::BlockScopeInfo>(CurFn))
1270 FunctionKind = Block;
1271 else if (isa<sema::LambdaScopeInfo>(CurFn))
1272 FunctionKind = Lambda;
1273 else if (isa<ObjCMethodDecl>(D))
1274 FunctionKind = Method;
1276 FunctionKind = Function;
1279 for (
const auto &P : UsesByStmt) {
1280 const Stmt *FirstRead = P.first;
1281 const WeakObjectProfileTy &Key = P.second->first;
1282 const WeakUseVector &Uses = P.second->second;
1290 if (Key.isExactProfile())
1291 DiagKind = diag::warn_arc_repeated_use_of_weak;
1293 DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
1306 if (isa<VarDecl>(D))
1307 ObjectKind = Variable;
1308 else if (isa<ObjCPropertyDecl>(D))
1310 else if (isa<ObjCMethodDecl>(D))
1311 ObjectKind = ImplicitProperty;
1312 else if (isa<ObjCIvarDecl>(D))
1315 llvm_unreachable(
"Unexpected weak object kind!");
1318 S.
Diag(FirstRead->getLocStart(), DiagKind)
1319 <<
int(ObjectKind) << D << int(FunctionKind)
1320 << FirstRead->getSourceRange();
1323 for (
const auto &Use : Uses) {
1324 if (Use.getUseExpr() == FirstRead)
1326 S.
Diag(Use.getUseExpr()->getLocStart(),
1327 diag::note_arc_weak_also_accessed_here)
1328 << Use.getUseExpr()->getSourceRange();
1337 typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
1341 typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
1345 UninitValsDiagReporter(
Sema &S) : S(S) {}
1348 MappedType &getUses(
const VarDecl *vd) {
1349 MappedType &V = uses[vd];
1350 if (!V.getPointer())
1351 V.setPointer(
new UsesVec());
1355 void handleUseOfUninitVariable(
const VarDecl *vd,
1357 getUses(vd).getPointer()->push_back(use);
1360 void handleSelfInit(
const VarDecl *vd)
override {
1361 getUses(vd).setInt(
true);
1365 for (
const auto &P : uses) {
1367 const MappedType &V = P.second;
1369 UsesVec *vec = V.getPointer();
1370 bool hasSelfInit = V.getInt();
1375 if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
1384 std::sort(vec->begin(), vec->end(),
1387 if (a.
getKind() != b.getKind())
1388 return a.
getKind() > b.getKind();
1389 return a.
getUser()->getLocStart() < b.getUser()->getLocStart();
1392 for (
const auto &U : *vec) {
1411 static bool hasAlwaysUninitializedUse(
const UsesVec* vec) {
1412 return std::any_of(vec->begin(), vec->end(), [](
const UninitUse &U) {
1424 typedef std::pair<PartialDiagnosticAt, OptionalNotes>
DelayedDiag;
1425 typedef std::list<DelayedDiag>
DiagList;
1427 struct SortDiagBySourceLocation {
1431 bool operator()(
const DelayedDiag &left,
const DelayedDiag &right) {
1444 namespace threadSafety {
1457 S.PDiag(diag::note_thread_warning_in_fun)
1468 S.PDiag(diag::note_thread_warning_in_fun)
1470 ONS.push_back(std::move(FNote));
1478 ONS.push_back(Note1);
1479 ONS.push_back(Note2);
1482 S.PDiag(diag::note_thread_warning_in_fun)
1484 ONS.push_back(std::move(FNote));
1490 void warnLockMismatch(
unsigned DiagID, StringRef
Kind,
Name LockName,
1497 Warnings.emplace_back(std::move(Warning), getNotes());
1505 void setVerbose(
bool b) {
Verbose = b; }
1511 void emitDiagnostics() {
1512 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
1514 S.Diag(
Diag.first.first,
Diag.first.second);
1515 for (
const auto &Note :
Diag.second)
1516 S.Diag(Note.first, Note.second);
1520 void handleInvalidLockExp(StringRef Kind,
SourceLocation Loc)
override {
1523 Warnings.emplace_back(std::move(Warning), getNotes());
1526 void handleUnmatchedUnlock(StringRef Kind,
Name LockName,
1528 warnLockMismatch(diag::warn_unlock_but_no_lock, Kind, LockName, Loc);
1531 void handleIncorrectUnlockKind(StringRef Kind,
Name LockName,
1537 << Kind << LockName << Received
1539 Warnings.emplace_back(std::move(Warning), getNotes());
1543 warnLockMismatch(diag::warn_double_lock, Kind, LockName, Loc);
1546 void handleMutexHeldEndOfScope(StringRef Kind,
Name LockName,
1550 unsigned DiagID = 0;
1553 DiagID = diag::warn_lock_some_predecessors;
1556 DiagID = diag::warn_expecting_lock_held_on_loop;
1559 DiagID = diag::warn_no_unlock;
1562 DiagID = diag::warn_expecting_locked;
1573 Warnings.emplace_back(std::move(Warning), getNotes(Note));
1576 Warnings.emplace_back(std::move(Warning), getNotes());
1579 void handleExclusiveAndShared(StringRef Kind,
Name LockName,
1583 S.PDiag(diag::warn_lock_exclusive_and_shared)
1584 << Kind << LockName);
1586 << Kind << LockName);
1587 Warnings.emplace_back(std::move(Warning), getNotes(Note));
1590 void handleNoMutexHeld(StringRef Kind,
const NamedDecl *D,
1594 "Only works for variables");
1596 diag::warn_variable_requires_any_lock:
1597 diag::warn_var_deref_requires_any_lock;
1600 Warnings.emplace_back(std::move(Warning), getNotes());
1603 void handleMutexNotHeld(StringRef Kind,
const NamedDecl *D,
1606 Name *PossibleMatch)
override {
1607 unsigned DiagID = 0;
1608 if (PossibleMatch) {
1611 DiagID = diag::warn_variable_requires_lock_precise;
1614 DiagID = diag::warn_var_deref_requires_lock_precise;
1617 DiagID = diag::warn_fun_requires_lock_precise;
1620 DiagID = diag::warn_guarded_pass_by_reference;
1623 DiagID = diag::warn_pt_guarded_pass_by_reference;
1633 S.PDiag(diag::note_guarded_by_declared_here)
1635 Warnings.emplace_back(std::move(Warning), getNotes(Note, VNote));
1637 Warnings.emplace_back(std::move(Warning), getNotes(Note));
1641 DiagID = diag::warn_variable_requires_lock;
1644 DiagID = diag::warn_var_deref_requires_lock;
1647 DiagID = diag::warn_fun_requires_lock;
1650 DiagID = diag::warn_guarded_pass_by_reference;
1653 DiagID = diag::warn_pt_guarded_pass_by_reference;
1661 S.PDiag(diag::note_guarded_by_declared_here)
1663 Warnings.emplace_back(std::move(Warning), getNotes(Note));
1665 Warnings.emplace_back(std::move(Warning), getNotes());
1669 void handleNegativeNotHeld(StringRef Kind,
Name LockName,
Name Neg,
1672 S.PDiag(diag::warn_acquire_requires_negative_cap)
1673 << Kind << LockName << Neg);
1674 Warnings.emplace_back(std::move(Warning), getNotes());
1677 void handleFunExcludesLock(StringRef Kind,
Name FunName,
Name LockName,
1680 << Kind << FunName << LockName);
1681 Warnings.emplace_back(std::move(Warning), getNotes());
1684 void handleLockAcquiredBefore(StringRef Kind,
Name L1Name,
Name L2Name,
1687 S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
1688 Warnings.emplace_back(std::move(Warning), getNotes());
1693 S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
1694 Warnings.emplace_back(std::move(Warning), getNotes());
1714 namespace consumed {
1716 class ConsumedWarningsHandler :
public ConsumedWarningsHandlerBase {
1723 ConsumedWarningsHandler(
Sema &S) : S(S) {}
1725 void emitDiagnostics()
override {
1726 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
1727 for (
const auto &
Diag : Warnings) {
1728 S.Diag(
Diag.first.first,
Diag.first.second);
1729 for (
const auto &Note :
Diag.second)
1730 S.Diag(Note.first, Note.second);
1735 StringRef VariableName)
override {
1743 StringRef VariableName,
1744 StringRef ExpectedState,
1745 StringRef ObservedState)
override {
1748 diag::warn_param_return_typestate_mismatch) << VariableName <<
1749 ExpectedState << ObservedState);
1754 void warnParamTypestateMismatch(
SourceLocation Loc, StringRef ExpectedState,
1755 StringRef ObservedState)
override {
1758 diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
1764 StringRef TypeName)
override {
1766 diag::warn_return_typestate_for_unconsumable_type) << TypeName);
1771 void warnReturnTypestateMismatch(
SourceLocation Loc, StringRef ExpectedState,
1772 StringRef ObservedState)
override {
1775 diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
1780 void warnUseOfTempInInvalidState(StringRef MethodName, StringRef
State,
1784 diag::warn_use_of_temp_in_invalid_state) << MethodName <<
State);
1789 void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
1793 MethodName << VariableName <<
State);
1808 enableCheckFallThrough = 1;
1809 enableCheckUnreachable = 0;
1810 enableThreadSafetyAnalysis = 0;
1811 enableConsumedAnalysis = 0;
1820 NumFunctionsAnalyzed(0),
1821 NumFunctionsWithBadCFGs(0),
1823 MaxCFGBlocksPerFunction(0),
1824 NumUninitAnalysisFunctions(0),
1825 NumUninitAnalysisVariables(0),
1826 MaxUninitAnalysisVariablesPerFunction(0),
1827 NumUninitAnalysisBlockVisits(0),
1828 MaxUninitAnalysisBlockVisitsPerFunction(0) {
1830 using namespace diag;
1833 DefaultPolicy.enableCheckUnreachable =
1836 isEnabled(D, warn_unreachable_return) ||
1837 isEnabled(D, warn_unreachable_loop_increment);
1839 DefaultPolicy.enableThreadSafetyAnalysis =
1842 DefaultPolicy.enableConsumedAnalysis =
1843 isEnabled(D, warn_use_in_invalid_state);
1848 S.
Diag(D.Loc, D.PD);
1871 if (cast<DeclContext>(D)->isDependentContext())
1880 const Stmt *Body = D->
getBody();
1902 if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||
1903 P.enableConsumedAnalysis) {
1920 std::unique_ptr<LogicalErrorHandler> LEH;
1921 if (!Diags.
isIgnored(diag::warn_tautological_overlap_comparison,
1923 LEH.reset(
new LogicalErrorHandler(S));
1929 bool analyzed =
false;
1940 bool processed =
false;
1951 S.Diag(D.Loc, D.PD);
1957 S.Diag(D.Loc, D.PD);
1967 if (P.enableCheckFallThrough) {
1968 const CheckFallThroughDiagnostics &CD =
1969 (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
1970 : (isa<CXXMethodDecl>(D) &&
1971 cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call &&
1972 cast<CXXMethodDecl>(D)->getParent()->isLambda())
1973 ? CheckFallThroughDiagnostics::MakeForLambda()
1974 : CheckFallThroughDiagnostics::MakeForFunction(D));
1979 if (P.enableCheckUnreachable) {
1984 bool isTemplateInstantiation =
false;
1985 if (
const FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
1986 isTemplateInstantiation = Function->isTemplateInstantiation();
1987 if (!isTemplateInstantiation)
1992 if (P.enableThreadSafetyAnalysis) {
1995 threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
1997 Reporter.setIssueBetaWarnings(
true);
1999 Reporter.setVerbose(
true);
2002 &S.ThreadSafetyDeclCache);
2003 Reporter.emitDiagnostics();
2007 if (P.enableConsumedAnalysis) {
2008 consumed::ConsumedWarningsHandler WarningHandler(S);
2017 UninitValsDiagReporter reporter(S);
2024 ++NumUninitAnalysisFunctions;
2027 MaxUninitAnalysisVariablesPerFunction =
2028 std::max(MaxUninitAnalysisVariablesPerFunction,
2030 MaxUninitAnalysisBlockVisitsPerFunction =
2031 std::max(MaxUninitAnalysisBlockVisitsPerFunction,
2037 bool FallThroughDiagFull =
2039 bool FallThroughDiagPerFunction = !Diags.
isIgnored(
2040 diag::warn_unannotated_fallthrough_per_function, D->
getLocStart());
2041 if (FallThroughDiagFull || FallThroughDiagPerFunction) {
2045 if (S.getLangOpts().ObjCWeak &&
2051 if (!Diags.
isIgnored(diag::warn_infinite_recursive_function,
2053 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
2060 if (!Diags.
isIgnored(diag::warn_tautological_overlap_comparison,
2067 ++NumFunctionsAnalyzed;
2071 NumCFGBlocks += cfg->getNumBlockIDs();
2072 MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
2073 cfg->getNumBlockIDs());
2075 ++NumFunctionsWithBadCFGs;
2081 llvm::errs() <<
"\n*** Analysis Based Warnings Stats:\n";
2083 unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
2084 unsigned AvgCFGBlocksPerFunction =
2085 !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
2086 llvm::errs() << NumFunctionsAnalyzed <<
" functions analyzed ("
2087 << NumFunctionsWithBadCFGs <<
" w/o CFGs).\n"
2088 <<
" " << NumCFGBlocks <<
" CFG blocks built.\n"
2089 <<
" " << AvgCFGBlocksPerFunction
2090 <<
" average CFG blocks per function.\n"
2091 <<
" " << MaxCFGBlocksPerFunction
2092 <<
" max CFG blocks per function.\n";
2094 unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
2095 : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
2096 unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
2097 : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
2098 llvm::errs() << NumUninitAnalysisFunctions
2099 <<
" functions analyzed for uninitialiazed variables\n"
2100 <<
" " << NumUninitAnalysisVariables <<
" variables analyzed.\n"
2101 <<
" " << AvgUninitVariablesPerFunction
2102 <<
" average variables per function.\n"
2103 <<
" " << MaxUninitAnalysisVariablesPerFunction
2104 <<
" max variables per function.\n"
2105 <<
" " << NumUninitAnalysisBlockVisits <<
" block visits.\n"
2106 <<
" " << AvgUninitBlockVisitsPerFunction
2107 <<
" average block visits per function.\n"
2108 <<
" " << MaxUninitAnalysisBlockVisitsPerFunction
2109 <<
" max block visits per function.\n";
StringRef getLastMacroWithSpelling(SourceLocation Loc, ArrayRef< TokenValue > Tokens) const
Return the name of the macro defined before Loc that has spelling Tokens.
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...
SourceLocation getEnd() const
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
Passing a guarded variable by reference.
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.
ASTContext & getASTContext() const
A (possibly-)qualified type.
SourceLocation getBegin() const
succ_iterator succ_begin()
const LangOptions & getLangOpts() const
FunctionType - C99 6.7.5.3 - Function Declarators.
IfStmt - This represents an if/then/else.
Defines the SourceManager interface.
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
static void diagnoseRepeatedUseOfWeak(Sema &S, const sema::FunctionScopeInfo *CurFn, const Decl *D, const ParentMap &PM)
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
Decl - This represents one declaration (or definition), e.g.
Represents an attribute applied to a statement.
The use is uninitialized whenever a certain branch is taken.
const Expr * getInit() const
AnalysisBasedWarnings(Sema &s)
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Calls Lexer::getLocForEndOfToken()
void run(AnalysisDeclContext &AC)
Check a function's CFG for consumed violations.
const Stmt * getElse() const
SourceLocation getOperatorLoc() const
bool isBlockPointerType() const
LockKind getLockKindFromAccessKind(AccessKind AK)
Helper function that returns a LockKind required for the given level of access.
SourceLocation getLocEnd() const LLVM_READONLY
unsigned IgnoreDefaultsWithCoveredEnums
static std::pair< const Stmt *, const CFGBlock * > getLastStmt(const ExplodedNode *Node)
branch_iterator branch_begin() const
Branches which inevitably result in the variable being used uninitialized.
ProtectedOperationKind
This enum distinguishes between different kinds of operations that may need to be protected by locks...
Retains information about a function, method, or block that is currently being parsed.
VarDecl - An instance of this class is created to represent a variable declaration or definition...
const Expr * getCallee() const
unsigned succ_size() const
ObjCMethodDecl - Represents an instance or class method declaration.
The use might be uninitialized.
Defines the Objective-C statement AST node classes.
Defines the clang::Expr interface and subclasses for C++ expressions.
SourceLocation getLocStart() const LLVM_READONLY
TextDiagnosticBuffer::DiagList DiagList
LabelStmt - Represents a label, which has a substatement.
LockKind
This enum distinguishes between different kinds of lock actions.
class LLVM_ALIGNAS(8) DependentTemplateSpecializationType const IdentifierInfo * Name
Represents a template specialization type whose template cannot be resolved, e.g. ...
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
std::pair< PartialDiagnosticAt, OptionalNotes > DelayedDiag
AnalysisDeclContext contains the context data for the function or method under analysis.
Expr * getImplicitObjectArgument() const
Retrieves the implicit object argument for the member call.
static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, bool PerFunction)
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type...
bool getAddEHEdges() const
getAddEHEdges - Return true iff we are adding exceptional edges from callExprs.
SmallVectorImpl< Branch >::const_iterator branch_iterator
const LangOptions & getLangOpts() const
bool AddCXXDefaultInitExprInCtors
CFGReverseBlockReachabilityAnalysis * getCFGReachablityAnalysis()
Concrete class used by the front-end to report problems and issues.
A builtin binary operation expression such as "x + y" or "x <= y".
void IssueWarnings(Policy P, FunctionScopeInfo *fscope, const Decl *D, const BlockExpr *blkExpr)
std::string getNameAsString() const
getNameAsString - Get a human-readable name for the declaration, even if it is one of the special kin...
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC)
CheckUnreachable - Check for unreachable code.
DeclContext * getLexicalDeclContext()
getLexicalDeclContext - The declaration context where this Decl was lexically declared (LexicalDC)...
const Decl * getDecl() const
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
A class that does preorder depth-first traversal on the entire Clang AST and visits each node...
detail::InMemoryDirectory::const_iterator I
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD)
const Expr * getUser() const
Get the expression containing the uninitialized use.
Passing a pt-guarded variable by reference.
ConditionalOperator - The ?: ternary operator.
Sema - This implements semantic analysis and AST building for C.
Expr * getFalseExpr() const
static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, const UninitUse &Use, bool alwaysReportSelfInit=false)
DiagnoseUninitializedUse – Helper function for diagnosing uses of an uninitialized variable...
CXXMethodDecl * getMethodDecl() const
Retrieves the declaration of the called method.
Handler class for thread safety warnings.
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to...
CFGBlock - Represents a single basic block in a source-level CFG.
std::vector< bool > & Stack
static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM, const Stmt *S)
Stmt * getBody() const
Get the body of the Declaration.
ID
Defines the set of possible language-specific address spaces.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Dereferencing a variable (e.g. p in *p = 5;)
Expr - This represents one expression.
bool hasFatalErrorOccurred() const
CFG - Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt...
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
Defines the clang::Preprocessor interface.
Stores token information for comparing actual tokens with predefined values.
void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats)
void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP, Callback &CB)
unsigned ScanReachableFromBlock(const CFGBlock *Start, llvm::BitVector &Reachable)
ScanReachableFromBlock - Mark all blocks reachable from Start.
const CFGBlock * getBlockForRegisteredExpression(const Stmt *stmt)
bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer...
unsigned getBlockID() const
AccessKind
This enum distinguishes between different ways to access (read or write) a variable.
Making a function call (e.g. fool())
DeclarationName getDeclName() const
getDeclName - Get the actual, stored name of the declaration, which may be a special name...
DiagnosticsEngine & getDiagnostics() const
A use of a variable, which might be uninitialized.
A type, stored as a Type*.
bool isTemplateInstantiation(TemplateSpecializationKind Kind)
Determine whether this template specialization kind refers to an instantiation of an entity (as oppos...
Expr * getTrueExpr() const
reverse_iterator rbegin()
static CharSourceRange getCharRange(SourceRange R)
bool getSuppressSystemWarnings() const
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
Stmt * getBody(const FunctionDecl *&Definition) const
getBody - Retrieve the body (definition) of the function.
bool isInMainFile(SourceLocation Loc) const
Returns whether the PresumedLoc for a given SourceLocation is in the main file.
SourceLocation getLocStart() const LLVM_READONLY
bool hasNoReturnElement() const
CFGTerminator getTerminator()
Reading or writing a variable (e.g. x in x = 5;)
Stmt * getParent(Stmt *) const
Encodes a location in the source.
BuildOptions & setAlwaysAdd(Stmt::StmtClass stmtClass, bool val=true)
bool isValid() const
Return true if this is a valid SourceLocation object.
bool isReachable(const CFGBlock *Src, const CFGBlock *Dst)
Returns true if the block 'Dst' can be reached from block 'Src'.
SourceLocation getLocStart() const LLVM_READONLY
Represents a call to a member function that may be written either with member call syntax (e...
ASTContext & getASTContext() const
bool PruneTriviallyFalseEdges
Represents a static or instance method of a struct/union/class.
bool isCFGBuilt() const
Returns true if we have built a CFG for this analysis context.
const Stmt * getStmt() const
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx)
SourceLocation FunLocation
std::pair< SourceLocation, PartialDiagnostic > PartialDiagnosticAt
A partial diagnostic along with the source location where this diagnostic occurs. ...
SourceLocation getBegin() const
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
static bool isLogicalOp(Opcode Opc)
BuildOptions & setAllAlwaysAdd()
The use is uninitialized the first time it is reached after we reach the variable's declaration...
bool isIgnored(unsigned DiagID, SourceLocation Loc) const
Determine whether the diagnostic is known to be ignored.
AdjacentBlocks::const_iterator const_succ_iterator
static unsigned isEnabled(DiagnosticsEngine &D, unsigned diag)
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, const BlockExpr *blkExpr, const CheckFallThroughDiagnostics &CD, AnalysisDeclContext &AC)
CheckFallThroughForFunctionDef - Check that we don't fall off the end of a function that should retur...
pred_iterator pred_begin()
CFG::BuildOptions & getCFGBuildOptions()
Return the build options used to construct the CFG.
SourceLocation FunEndLocation
TemplatedKind getTemplatedKind() const
What kind of templated function this is.
void runThreadSafetyAnalysis(AnalysisDeclContext &AC, ThreadSafetyHandler &Handler, BeforeSet **Bset)
Check a function's CFG for thread-safety violations.
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...
llvm::SmallDenseMap< WeakObjectProfileTy, WeakUseVector, 8, WeakObjectProfileTy::DenseMapInfo > WeakObjectUseMap
Used to collect all uses of weak objects in a function body.
std::string getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const
Get a string to suggest for zero-initialization of a type.
static FixItHint CreateRemoval(CharSourceRange RemoveRange)
Create a code modification hint that removes the given source range.
static bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg)
SmallVector< PartialDiagnosticAt, 1 > OptionalNotes
const WeakObjectUseMap & getWeakObjectUses() const
Represents a simple identification of a weak object.
SourceLocation getLocStart() const LLVM_READONLY
detail::InMemoryDirectory::const_iterator E
A class that handles the analysis of uniqueness violations.
ConstEvaluatedExprVisitor - This class visits 'const Expr *'s.
Expr * IgnoreParenImpCasts() LLVM_READONLY
IgnoreParenImpCasts - Ignore parentheses and implicit casts.
const Stmt * getThen() const
SwitchStmt - This represents a 'switch' stmt.
Kind getKind() const
Get the kind of uninitialized use.
UnreachableKind
Classifications of unreachable code.
SourceManager & getSourceManager() const
const T * getAs() const
Member-template getAs<specific type>'.
QualType getCanonicalType() const
The use is always uninitialized.
static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, const Stmt *Body, AnalysisDeclContext &AC)
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.
SourceLocation getExprLoc() const LLVM_READONLY
static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
Defines the clang::SourceLocation class and associated facilities.
SmallVector< PossiblyUnreachableDiag, 4 > PossiblyUnreachableDiags
A list of PartialDiagnostics created but delayed within the current function scope.
CFGCallback defines methods that should be called when a logical operator error is found when buildin...
const Expr * getCond() const
CFGElement - Represents a top-level expression in a basic block.
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string...
static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC)
CheckFallThrough - Check that we don't fall off the end of a Statement that should return a value...
The use is uninitialized the first time it is reached after the function is called.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
void registerForcedBlockExpression(const Stmt *stmt)
A reference to a declared variable, function, enum, etc.
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
const FunctionDecl * CurrentFunction
unsigned NumVariablesAnalyzed
ParentMap & getParentMap()
A trivial tuple used to represent a source range.
SourceLocation getLocation() const
FunctionDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
NamedDecl - This represents a decl with a name.
bool hasUncompilableErrorOccurred() const
Errors that actually prevent compilation, not those that are upgraded from a warning by -Werror...
unsigned getNumBlockIDs() const
getNumBlockIDs - Returns the total number of BlockIDs allocated (which start at 0).
branch_iterator branch_end() const
static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block)
This class handles loading and caching of source files into memory.
Preprocessor & getPreprocessor() const
Optional< T > getAs() const
Convert to the specified CFGElement type, returning None if this CFGElement is not of the desired typ...
Engages in a tight little dance with the lexer to efficiently preprocess tokens.