1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | #include "clang/Analysis/Analyses/ReachableCode.h" |
15 | #include "clang/AST/Expr.h" |
16 | #include "clang/AST/ExprCXX.h" |
17 | #include "clang/AST/ExprObjC.h" |
18 | #include "clang/AST/ParentMap.h" |
19 | #include "clang/AST/StmtCXX.h" |
20 | #include "clang/Analysis/AnalysisDeclContext.h" |
21 | #include "clang/Analysis/CFG.h" |
22 | #include "clang/Basic/SourceManager.h" |
23 | #include "clang/Lex/Preprocessor.h" |
24 | #include "llvm/ADT/BitVector.h" |
25 | #include "llvm/ADT/SmallVector.h" |
26 | |
27 | using namespace clang; |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | static bool isEnumConstant(const Expr *Ex) { |
34 | const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex); |
35 | if (!DR) |
36 | return false; |
37 | return isa<EnumConstantDecl>(DR->getDecl()); |
38 | } |
39 | |
40 | static bool isTrivialExpression(const Expr *Ex) { |
41 | Ex = Ex->IgnoreParenCasts(); |
42 | return isa<IntegerLiteral>(Ex) || isa<StringLiteral>(Ex) || |
43 | isa<CXXBoolLiteralExpr>(Ex) || isa<ObjCBoolLiteralExpr>(Ex) || |
44 | isa<CharacterLiteral>(Ex) || |
45 | isEnumConstant(Ex); |
46 | } |
47 | |
48 | static bool isTrivialDoWhile(const CFGBlock *B, const Stmt *S) { |
49 | |
50 | |
51 | if (const Stmt *Term = B->getTerminator()) { |
52 | if (const DoStmt *DS = dyn_cast<DoStmt>(Term)) { |
53 | const Expr *Cond = DS->getCond()->IgnoreParenCasts(); |
54 | return Cond == S && isTrivialExpression(Cond); |
55 | } |
56 | } |
57 | return false; |
58 | } |
59 | |
60 | static bool isBuiltinUnreachable(const Stmt *S) { |
61 | if (const auto *DRE = dyn_cast<DeclRefExpr>(S)) |
62 | if (const auto *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl())) |
63 | return FDecl->getIdentifier() && |
64 | FDecl->getBuiltinID() == Builtin::BI__builtin_unreachable; |
65 | return false; |
66 | } |
67 | |
68 | static bool isBuiltinAssumeFalse(const CFGBlock *B, const Stmt *S, |
69 | ASTContext &C) { |
70 | if (B->empty()) { |
71 | |
72 | |
73 | return false; |
74 | } |
75 | if (Optional<CFGStmt> CS = B->back().getAs<CFGStmt>()) { |
76 | if (const auto *CE = dyn_cast<CallExpr>(CS->getStmt())) { |
77 | return CE->getCallee()->IgnoreCasts() == S && CE->isBuiltinAssumeFalse(C); |
78 | } |
79 | } |
80 | return false; |
81 | } |
82 | |
83 | static bool isDeadReturn(const CFGBlock *B, const Stmt *S) { |
84 | |
85 | |
86 | |
87 | const CFGBlock *Current = B; |
88 | while (true) { |
89 | for (CFGBlock::const_reverse_iterator I = Current->rbegin(), |
90 | E = Current->rend(); |
91 | I != E; ++I) { |
92 | if (Optional<CFGStmt> CS = I->getAs<CFGStmt>()) { |
93 | if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(CS->getStmt())) { |
94 | if (RS == S) |
95 | return true; |
96 | if (const Expr *RE = RS->getRetValue()) { |
97 | RE = RE->IgnoreParenCasts(); |
98 | if (RE == S) |
99 | return true; |
100 | ParentMap PM(const_cast<Expr *>(RE)); |
101 | |
102 | |
103 | return PM.getParent(S); |
104 | } |
105 | } |
106 | break; |
107 | } |
108 | } |
109 | |
110 | |
111 | |
112 | if (Current->getTerminator().isTemporaryDtorsBranch()) { |
113 | |
114 | |
115 | |
116 | |
117 | succ_size() == 2", "/home/seafit/code_projects/clang_source/clang/lib/Analysis/ReachableCode.cpp", 117, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Current->succ_size() == 2); |
118 | Current = *(Current->succ_begin() + 1); |
119 | } else if (!Current->getTerminator() && Current->succ_size() == 1) { |
120 | |
121 | |
122 | Current = *Current->succ_begin(); |
123 | if (Current->pred_size() > 1) { |
124 | |
125 | |
126 | |
127 | return false; |
128 | } |
129 | } else { |
130 | |
131 | return false; |
132 | } |
133 | } |
134 | llvm_unreachable("Broke out of infinite loop."); |
135 | } |
136 | |
137 | static SourceLocation getTopMostMacro(SourceLocation Loc, SourceManager &SM) { |
138 | assert(Loc.isMacroID()); |
139 | SourceLocation Last; |
140 | while (Loc.isMacroID()) { |
141 | Last = Loc; |
142 | Loc = SM.getImmediateMacroCallerLoc(Loc); |
143 | } |
144 | return Last; |
145 | } |
146 | |
147 | |
148 | static bool isExpandedFromConfigurationMacro(const Stmt *S, |
149 | Preprocessor &PP, |
150 | bool IgnoreYES_NO = false) { |
151 | |
152 | |
153 | |
154 | |
155 | SourceLocation L = S->getBeginLoc(); |
156 | if (L.isMacroID()) { |
157 | SourceManager &SM = PP.getSourceManager(); |
158 | if (IgnoreYES_NO) { |
159 | |
160 | |
161 | |
162 | SourceLocation TopL = getTopMostMacro(L, SM); |
163 | StringRef MacroName = PP.getImmediateMacroName(TopL); |
164 | if (MacroName == "YES" || MacroName == "NO") |
165 | return false; |
166 | } else if (!PP.getLangOpts().CPlusPlus) { |
167 | |
168 | SourceLocation TopL = getTopMostMacro(L, SM); |
169 | StringRef MacroName = PP.getImmediateMacroName(TopL); |
170 | if (MacroName == "false" || MacroName == "true") |
171 | return false; |
172 | } |
173 | return true; |
174 | } |
175 | return false; |
176 | } |
177 | |
178 | static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP); |
179 | |
180 | |
181 | |
182 | |
183 | |
184 | |
185 | |
186 | |
187 | static bool isConfigurationValue(const Stmt *S, |
188 | Preprocessor &PP, |
189 | SourceRange *SilenceableCondVal = nullptr, |
190 | bool IncludeIntegers = true, |
191 | bool WrappedInParens = false) { |
192 | if (!S) |
193 | return false; |
194 | |
195 | if (const auto *Ex = dyn_cast<Expr>(S)) |
196 | S = Ex->IgnoreImplicit(); |
197 | |
198 | if (const auto *Ex = dyn_cast<Expr>(S)) |
199 | S = Ex->IgnoreCasts(); |
200 | |
201 | |
202 | if (const ParenExpr *PE = dyn_cast<ParenExpr>(S)) |
203 | if (!PE->getBeginLoc().isMacroID()) |
204 | return isConfigurationValue(PE->getSubExpr(), PP, SilenceableCondVal, |
205 | IncludeIntegers, true); |
206 | |
207 | if (const Expr *Ex = dyn_cast<Expr>(S)) |
208 | S = Ex->IgnoreCasts(); |
209 | |
210 | bool IgnoreYES_NO = false; |
211 | |
212 | switch (S->getStmtClass()) { |
213 | case Stmt::CallExprClass: { |
214 | const FunctionDecl *Callee = |
215 | dyn_cast_or_null<FunctionDecl>(cast<CallExpr>(S)->getCalleeDecl()); |
216 | return Callee ? Callee->isConstexpr() : false; |
217 | } |
218 | case Stmt::DeclRefExprClass: |
219 | return isConfigurationValue(cast<DeclRefExpr>(S)->getDecl(), PP); |
220 | case Stmt::ObjCBoolLiteralExprClass: |
221 | IgnoreYES_NO = true; |
222 | LLVM_FALLTHROUGH; |
223 | case Stmt::CXXBoolLiteralExprClass: |
224 | case Stmt::IntegerLiteralClass: { |
225 | const Expr *E = cast<Expr>(S); |
226 | if (IncludeIntegers) { |
227 | if (SilenceableCondVal && !SilenceableCondVal->getBegin().isValid()) |
228 | *SilenceableCondVal = E->getSourceRange(); |
229 | return WrappedInParens || isExpandedFromConfigurationMacro(E, PP, IgnoreYES_NO); |
230 | } |
231 | return false; |
232 | } |
233 | case Stmt::MemberExprClass: |
234 | return isConfigurationValue(cast<MemberExpr>(S)->getMemberDecl(), PP); |
235 | case Stmt::UnaryExprOrTypeTraitExprClass: |
236 | return true; |
237 | case Stmt::BinaryOperatorClass: { |
238 | const BinaryOperator *B = cast<BinaryOperator>(S); |
239 | |
240 | |
241 | |
242 | IncludeIntegers &= (B->isLogicalOp() || B->isComparisonOp()); |
243 | return isConfigurationValue(B->getLHS(), PP, SilenceableCondVal, |
244 | IncludeIntegers) || |
245 | isConfigurationValue(B->getRHS(), PP, SilenceableCondVal, |
246 | IncludeIntegers); |
247 | } |
248 | case Stmt::UnaryOperatorClass: { |
249 | const UnaryOperator *UO = cast<UnaryOperator>(S); |
250 | if (UO->getOpcode() != UO_LNot) |
251 | return false; |
252 | bool SilenceableCondValNotSet = |
253 | SilenceableCondVal && SilenceableCondVal->getBegin().isInvalid(); |
254 | bool IsSubExprConfigValue = |
255 | isConfigurationValue(UO->getSubExpr(), PP, SilenceableCondVal, |
256 | IncludeIntegers, WrappedInParens); |
257 | |
258 | |
259 | if (SilenceableCondValNotSet && |
260 | SilenceableCondVal->getBegin().isValid() && |
261 | *SilenceableCondVal == |
262 | UO->getSubExpr()->IgnoreCasts()->getSourceRange()) |
263 | *SilenceableCondVal = UO->getSourceRange(); |
264 | return IsSubExprConfigValue; |
265 | } |
266 | default: |
267 | return false; |
268 | } |
269 | } |
270 | |
271 | static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP) { |
272 | if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D)) |
273 | return isConfigurationValue(ED->getInitExpr(), PP); |
274 | if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { |
275 | |
276 | |
277 | |
278 | |
279 | |
280 | |
281 | |
282 | if (!VD->hasLocalStorage()) |
283 | return true; |
284 | |
285 | |
286 | |
287 | return VD->getType().isLocalConstQualified(); |
288 | } |
289 | return false; |
290 | } |
291 | |
292 | |
293 | static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B, |
294 | Preprocessor &PP) { |
295 | if (const Stmt *Term = B->getTerminator()) { |
296 | if (isa<SwitchStmt>(Term)) |
297 | return true; |
298 | |
299 | if (isa<BinaryOperator>(Term)) { |
300 | return isConfigurationValue(Term, PP); |
301 | } |
302 | } |
303 | |
304 | const Stmt *Cond = B->getTerminatorCondition( false); |
305 | return isConfigurationValue(Cond, PP); |
306 | } |
307 | |
308 | static unsigned scanFromBlock(const CFGBlock *Start, |
309 | llvm::BitVector &Reachable, |
310 | Preprocessor *PP, |
311 | bool IncludeSometimesUnreachableEdges) { |
312 | unsigned count = 0; |
313 | |
314 | |
315 | SmallVector<const CFGBlock*, 32> WL; |
316 | |
317 | |
318 | |
319 | if (!Reachable[Start->getBlockID()]) { |
320 | ++count; |
321 | Reachable[Start->getBlockID()] = true; |
322 | } |
323 | |
324 | WL.push_back(Start); |
325 | |
326 | |
327 | while (!WL.empty()) { |
328 | const CFGBlock *item = WL.pop_back_val(); |
329 | |
330 | |
331 | |
332 | |
333 | |
334 | |
335 | |
336 | Optional<bool> TreatAllSuccessorsAsReachable; |
337 | if (!IncludeSometimesUnreachableEdges) |
338 | TreatAllSuccessorsAsReachable = false; |
339 | |
340 | for (CFGBlock::const_succ_iterator I = item->succ_begin(), |
341 | E = item->succ_end(); I != E; ++I) { |
342 | const CFGBlock *B = *I; |
343 | if (!B) do { |
344 | const CFGBlock *UB = I->getPossiblyUnreachableBlock(); |
345 | if (!UB) |
346 | break; |
347 | |
348 | if (!TreatAllSuccessorsAsReachable.hasValue()) { |
349 | assert(PP); |
350 | TreatAllSuccessorsAsReachable = |
351 | shouldTreatSuccessorsAsReachable(item, *PP); |
352 | } |
353 | |
354 | if (TreatAllSuccessorsAsReachable.getValue()) { |
355 | B = UB; |
356 | break; |
357 | } |
358 | } |
359 | while (false); |
360 | |
361 | if (B) { |
362 | unsigned blockID = B->getBlockID(); |
363 | if (!Reachable[blockID]) { |
364 | Reachable.set(blockID); |
365 | WL.push_back(B); |
366 | ++count; |
367 | } |
368 | } |
369 | } |
370 | } |
371 | return count; |
372 | } |
373 | |
374 | static unsigned scanMaybeReachableFromBlock(const CFGBlock *Start, |
375 | Preprocessor &PP, |
376 | llvm::BitVector &Reachable) { |
377 | return scanFromBlock(Start, Reachable, &PP, true); |
378 | } |
379 | |
380 | |
381 | |
382 | |
383 | |
384 | namespace { |
385 | class DeadCodeScan { |
386 | llvm::BitVector Visited; |
387 | llvm::BitVector &Reachable; |
388 | SmallVector<const CFGBlock *, 10> WorkList; |
389 | Preprocessor &PP; |
390 | ASTContext &C; |
391 | |
392 | typedef SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12> |
393 | DeferredLocsTy; |
394 | |
395 | DeferredLocsTy DeferredLocs; |
396 | |
397 | public: |
398 | DeadCodeScan(llvm::BitVector &reachable, Preprocessor &PP, ASTContext &C) |
399 | : Visited(reachable.size()), |
400 | Reachable(reachable), |
401 | PP(PP), C(C) {} |
402 | |
403 | void enqueue(const CFGBlock *block); |
404 | unsigned scanBackwards(const CFGBlock *Start, |
405 | clang::reachable_code::Callback &CB); |
406 | |
407 | bool isDeadCodeRoot(const CFGBlock *Block); |
408 | |
409 | const Stmt *findDeadCode(const CFGBlock *Block); |
410 | |
411 | void reportDeadCode(const CFGBlock *B, |
412 | const Stmt *S, |
413 | clang::reachable_code::Callback &CB); |
414 | }; |
415 | } |
416 | |
417 | void DeadCodeScan::enqueue(const CFGBlock *block) { |
418 | unsigned blockID = block->getBlockID(); |
419 | if (Reachable[blockID] || Visited[blockID]) |
420 | return; |
421 | Visited[blockID] = true; |
422 | WorkList.push_back(block); |
423 | } |
424 | |
425 | bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) { |
426 | bool isDeadRoot = true; |
427 | |
428 | for (CFGBlock::const_pred_iterator I = Block->pred_begin(), |
429 | E = Block->pred_end(); I != E; ++I) { |
430 | if (const CFGBlock *PredBlock = *I) { |
431 | unsigned blockID = PredBlock->getBlockID(); |
432 | if (Visited[blockID]) { |
433 | isDeadRoot = false; |
434 | continue; |
435 | } |
436 | if (!Reachable[blockID]) { |
437 | isDeadRoot = false; |
438 | Visited[blockID] = true; |
439 | WorkList.push_back(PredBlock); |
440 | continue; |
441 | } |
442 | } |
443 | } |
444 | |
445 | return isDeadRoot; |
446 | } |
447 | |
448 | static bool isValidDeadStmt(const Stmt *S) { |
449 | if (S->getBeginLoc().isInvalid()) |
450 | return false; |
451 | if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) |
452 | return BO->getOpcode() != BO_Comma; |
453 | return true; |
454 | } |
455 | |
456 | const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) { |
457 | for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I!=E; ++I) |
458 | if (Optional<CFGStmt> CS = I->getAs<CFGStmt>()) { |
459 | const Stmt *S = CS->getStmt(); |
460 | if (isValidDeadStmt(S)) |
461 | return S; |
462 | } |
463 | |
464 | if (CFGTerminator T = Block->getTerminator()) { |
465 | if (!T.isTemporaryDtorsBranch()) { |
466 | const Stmt *S = T.getStmt(); |
467 | if (isValidDeadStmt(S)) |
468 | return S; |
469 | } |
470 | } |
471 | |
472 | return nullptr; |
473 | } |
474 | |
475 | static int SrcCmp(const std::pair<const CFGBlock *, const Stmt *> *p1, |
476 | const std::pair<const CFGBlock *, const Stmt *> *p2) { |
477 | if (p1->second->getBeginLoc() < p2->second->getBeginLoc()) |
478 | return -1; |
479 | if (p2->second->getBeginLoc() < p1->second->getBeginLoc()) |
480 | return 1; |
481 | return 0; |
482 | } |
483 | |
484 | unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start, |
485 | clang::reachable_code::Callback &CB) { |
486 | |
487 | unsigned count = 0; |
488 | enqueue(Start); |
489 | |
490 | while (!WorkList.empty()) { |
491 | const CFGBlock *Block = WorkList.pop_back_val(); |
492 | |
493 | |
494 | |
495 | if (Reachable[Block->getBlockID()]) |
496 | continue; |
497 | |
498 | |
499 | const Stmt *S = findDeadCode(Block); |
500 | |
501 | if (!S) { |
502 | |
503 | for (CFGBlock::const_pred_iterator I = Block->pred_begin(), |
504 | E = Block->pred_end(); I != E; ++I) { |
505 | if (const CFGBlock *predBlock = *I) |
506 | enqueue(predBlock); |
507 | } |
508 | continue; |
509 | } |
510 | |
511 | |
512 | if (S->getBeginLoc().isMacroID()) { |
513 | count += scanMaybeReachableFromBlock(Block, PP, Reachable); |
514 | continue; |
515 | } |
516 | |
517 | if (isDeadCodeRoot(Block)) { |
518 | reportDeadCode(Block, S, CB); |
519 | count += scanMaybeReachableFromBlock(Block, PP, Reachable); |
520 | } |
521 | else { |
522 | |
523 | |
524 | |
525 | DeferredLocs.push_back(std::make_pair(Block, S)); |
526 | } |
527 | } |
528 | |
529 | |
530 | |
531 | if (!DeferredLocs.empty()) { |
532 | llvm::array_pod_sort(DeferredLocs.begin(), DeferredLocs.end(), SrcCmp); |
533 | for (DeferredLocsTy::iterator I = DeferredLocs.begin(), |
534 | E = DeferredLocs.end(); I != E; ++I) { |
535 | const CFGBlock *Block = I->first; |
536 | if (Reachable[Block->getBlockID()]) |
537 | continue; |
538 | reportDeadCode(Block, I->second, CB); |
539 | count += scanMaybeReachableFromBlock(Block, PP, Reachable); |
540 | } |
541 | } |
542 | |
543 | return count; |
544 | } |
545 | |
546 | static SourceLocation GetUnreachableLoc(const Stmt *S, |
547 | SourceRange &R1, |
548 | SourceRange &R2) { |
549 | R1 = R2 = SourceRange(); |
550 | |
551 | if (const Expr *Ex = dyn_cast<Expr>(S)) |
552 | S = Ex->IgnoreParenImpCasts(); |
553 | |
554 | switch (S->getStmtClass()) { |
555 | case Expr::BinaryOperatorClass: { |
556 | const BinaryOperator *BO = cast<BinaryOperator>(S); |
557 | return BO->getOperatorLoc(); |
558 | } |
559 | case Expr::UnaryOperatorClass: { |
560 | const UnaryOperator *UO = cast<UnaryOperator>(S); |
561 | R1 = UO->getSubExpr()->getSourceRange(); |
562 | return UO->getOperatorLoc(); |
563 | } |
564 | case Expr::CompoundAssignOperatorClass: { |
565 | const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S); |
566 | R1 = CAO->getLHS()->getSourceRange(); |
567 | R2 = CAO->getRHS()->getSourceRange(); |
568 | return CAO->getOperatorLoc(); |
569 | } |
570 | case Expr::BinaryConditionalOperatorClass: |
571 | case Expr::ConditionalOperatorClass: { |
572 | const AbstractConditionalOperator *CO = |
573 | cast<AbstractConditionalOperator>(S); |
574 | return CO->getQuestionLoc(); |
575 | } |
576 | case Expr::MemberExprClass: { |
577 | const MemberExpr *ME = cast<MemberExpr>(S); |
578 | R1 = ME->getSourceRange(); |
579 | return ME->getMemberLoc(); |
580 | } |
581 | case Expr::ArraySubscriptExprClass: { |
582 | const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S); |
583 | R1 = ASE->getLHS()->getSourceRange(); |
584 | R2 = ASE->getRHS()->getSourceRange(); |
585 | return ASE->getRBracketLoc(); |
586 | } |
587 | case Expr::CStyleCastExprClass: { |
588 | const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S); |
589 | R1 = CSC->getSubExpr()->getSourceRange(); |
590 | return CSC->getLParenLoc(); |
591 | } |
592 | case Expr::CXXFunctionalCastExprClass: { |
593 | const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S); |
594 | R1 = CE->getSubExpr()->getSourceRange(); |
595 | return CE->getBeginLoc(); |
596 | } |
597 | case Stmt::CXXTryStmtClass: { |
598 | return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc(); |
599 | } |
600 | case Expr::ObjCBridgedCastExprClass: { |
601 | const ObjCBridgedCastExpr *CSC = cast<ObjCBridgedCastExpr>(S); |
602 | R1 = CSC->getSubExpr()->getSourceRange(); |
603 | return CSC->getLParenLoc(); |
604 | } |
605 | default: ; |
606 | } |
607 | R1 = S->getSourceRange(); |
608 | return S->getBeginLoc(); |
609 | } |
610 | |
611 | void DeadCodeScan::reportDeadCode(const CFGBlock *B, |
612 | const Stmt *S, |
613 | clang::reachable_code::Callback &CB) { |
614 | |
615 | reachable_code::UnreachableKind UK = reachable_code::UK_Other; |
616 | |
617 | if (isa<BreakStmt>(S)) { |
618 | UK = reachable_code::UK_Break; |
619 | } else if (isTrivialDoWhile(B, S) || isBuiltinUnreachable(S) || |
620 | isBuiltinAssumeFalse(B, S, C)) { |
621 | return; |
622 | } |
623 | else if (isDeadReturn(B, S)) { |
624 | UK = reachable_code::UK_Return; |
625 | } |
626 | |
627 | SourceRange SilenceableCondVal; |
628 | |
629 | if (UK == reachable_code::UK_Other) { |
630 | |
631 | |
632 | |
633 | if (const Stmt *LoopTarget = B->getLoopTarget()) { |
634 | SourceLocation Loc = LoopTarget->getBeginLoc(); |
635 | SourceRange R1(Loc, Loc), R2; |
636 | |
637 | if (const ForStmt *FS = dyn_cast<ForStmt>(LoopTarget)) { |
638 | const Expr *Inc = FS->getInc(); |
639 | Loc = Inc->getBeginLoc(); |
640 | R2 = Inc->getSourceRange(); |
641 | } |
642 | |
643 | CB.HandleUnreachable(reachable_code::UK_Loop_Increment, |
644 | Loc, SourceRange(), SourceRange(Loc, Loc), R2); |
645 | return; |
646 | } |
647 | |
648 | |
649 | |
650 | |
651 | CFGBlock::const_pred_iterator PI = B->pred_begin(); |
652 | if (PI != B->pred_end()) { |
653 | if (const CFGBlock *PredBlock = PI->getPossiblyUnreachableBlock()) { |
654 | const Stmt *TermCond = |
655 | PredBlock->getTerminatorCondition( false); |
656 | isConfigurationValue(TermCond, PP, &SilenceableCondVal); |
657 | } |
658 | } |
659 | } |
660 | |
661 | SourceRange R1, R2; |
662 | SourceLocation Loc = GetUnreachableLoc(S, R1, R2); |
663 | CB.HandleUnreachable(UK, Loc, SilenceableCondVal, R1, R2); |
664 | } |
665 | |
666 | |
667 | |
668 | |
669 | |
670 | namespace clang { namespace reachable_code { |
671 | |
672 | void Callback::anchor() { } |
673 | |
674 | unsigned ScanReachableFromBlock(const CFGBlock *Start, |
675 | llvm::BitVector &Reachable) { |
676 | return scanFromBlock(Start, Reachable, nullptr, false); |
677 | } |
678 | |
679 | void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP, |
680 | Callback &CB) { |
681 | |
682 | CFG *cfg = AC.getCFG(); |
683 | if (!cfg) |
684 | return; |
685 | |
686 | |
687 | |
688 | llvm::BitVector reachable(cfg->getNumBlockIDs()); |
689 | unsigned numReachable = |
690 | scanMaybeReachableFromBlock(&cfg->getEntry(), PP, reachable); |
691 | if (numReachable == cfg->getNumBlockIDs()) |
692 | return; |
693 | |
694 | |
695 | |
696 | if (!AC.getCFGBuildOptions().AddEHEdges) { |
697 | for (CFG::try_block_iterator I = cfg->try_blocks_begin(), |
698 | E = cfg->try_blocks_end() ; I != E; ++I) { |
699 | numReachable += scanMaybeReachableFromBlock(*I, PP, reachable); |
700 | } |
701 | if (numReachable == cfg->getNumBlockIDs()) |
702 | return; |
703 | } |
704 | |
705 | |
706 | |
707 | for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { |
708 | const CFGBlock *block = *I; |
709 | |
710 | if (reachable[block->getBlockID()]) |
711 | continue; |
712 | |
713 | DeadCodeScan DS(reachable, PP, AC.getASTContext()); |
714 | numReachable += DS.scanBackwards(block, CB); |
715 | |
716 | if (numReachable == cfg->getNumBlockIDs()) |
717 | return; |
718 | } |
719 | } |
720 | |
721 | }} |
722 | |