blob: 9eb5b7f5a58ff3c425c60fe16d32bd90df42e662 [file] [log] [blame]
Ted Kremenekdbdbaaf2010-03-20 21:06:02 +00001//=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- C++ -*-=//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines analysis_warnings::[Policy,Executor].
11// Together they are used by Sema to issue warnings based on inexpensive
12// static analysis algorithms in libAnalysis.
13//
14//===----------------------------------------------------------------------===//
15
16#include "Sema.h"
17#include "AnalysisBasedWarnings.h"
18#include "clang/AST/ExprObjC.h"
19#include "clang/AST/ExprCXX.h"
20#include "clang/AST/StmtObjC.h"
21#include "clang/AST/StmtCXX.h"
22#include "clang/Analysis/AnalysisContext.h"
23#include "clang/Analysis/CFG.h"
24#include "clang/Analysis/Analyses/ReachableCode.h"
25#include "llvm/ADT/BitVector.h"
26#include "llvm/Support/Casting.h"
27#include <queue>
28
29using namespace clang;
30
31//===----------------------------------------------------------------------===//
32// Unreachable code analysis.
33//===----------------------------------------------------------------------===//
34
35namespace {
36 class UnreachableCodeHandler : public reachable_code::Callback {
37 Sema &S;
38 public:
39 UnreachableCodeHandler(Sema &s) : S(s) {}
40
41 void HandleUnreachable(SourceLocation L, SourceRange R1, SourceRange R2) {
42 S.Diag(L, diag::warn_unreachable) << R1 << R2;
43 }
44 };
45}
46
47/// CheckUnreachable - Check for unreachable code.
48static void CheckUnreachable(Sema &S, AnalysisContext &AC) {
49 UnreachableCodeHandler UC(S);
50 reachable_code::FindUnreachableCode(AC, UC);
51}
52
53//===----------------------------------------------------------------------===//
54// Check for missing return value.
55//===----------------------------------------------------------------------===//
56
57enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1,
58 AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 };
59
60/// CheckFallThrough - Check that we don't fall off the end of a
61/// Statement that should return a value.
62///
63/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
64/// MaybeFallThrough iff we might or might not fall off the end,
65/// NeverFallThroughOrReturn iff we never fall off the end of the statement or
66/// return. We assume NeverFallThrough iff we never fall off the end of the
67/// statement but we may return. We assume that functions not marked noreturn
68/// will return.
69static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
70 CFG *cfg = AC.getCFG();
71 if (cfg == 0)
72 // FIXME: This should be NeverFallThrough
73 return NeverFallThroughOrReturn;
74
75 // The CFG leaves in dead things, and we don't want the dead code paths to
76 // confuse us, so we mark all live things first.
77 std::queue<CFGBlock*> workq;
78 llvm::BitVector live(cfg->getNumBlockIDs());
79 unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(),
80 live);
81
82 bool AddEHEdges = AC.getAddEHEdges();
83 if (!AddEHEdges && count != cfg->getNumBlockIDs())
84 // When there are things remaining dead, and we didn't add EH edges
85 // from CallExprs to the catch clauses, we have to go back and
86 // mark them as live.
87 for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
88 CFGBlock &b = **I;
89 if (!live[b.getBlockID()]) {
90 if (b.pred_begin() == b.pred_end()) {
91 if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator()))
92 // When not adding EH edges from calls, catch clauses
93 // can otherwise seem dead. Avoid noting them as dead.
94 count += reachable_code::ScanReachableFromBlock(b, live);
95 continue;
96 }
97 }
98 }
99
100 // Now we know what is live, we check the live precessors of the exit block
101 // and look for fall through paths, being careful to ignore normal returns,
102 // and exceptional paths.
103 bool HasLiveReturn = false;
104 bool HasFakeEdge = false;
105 bool HasPlainEdge = false;
106 bool HasAbnormalEdge = false;
107 for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(),
108 E = cfg->getExit().pred_end();
109 I != E;
110 ++I) {
111 CFGBlock& B = **I;
112 if (!live[B.getBlockID()])
113 continue;
114 if (B.size() == 0) {
115 if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) {
116 HasAbnormalEdge = true;
117 continue;
118 }
119
120 // A labeled empty statement, or the entry block...
121 HasPlainEdge = true;
122 continue;
123 }
124 Stmt *S = B[B.size()-1];
125 if (isa<ReturnStmt>(S)) {
126 HasLiveReturn = true;
127 continue;
128 }
129 if (isa<ObjCAtThrowStmt>(S)) {
130 HasFakeEdge = true;
131 continue;
132 }
133 if (isa<CXXThrowExpr>(S)) {
134 HasFakeEdge = true;
135 continue;
136 }
137 if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {
138 if (AS->isMSAsm()) {
139 HasFakeEdge = true;
140 HasLiveReturn = true;
141 continue;
142 }
143 }
144 if (isa<CXXTryStmt>(S)) {
145 HasAbnormalEdge = true;
146 continue;
147 }
148
149 bool NoReturnEdge = false;
150 if (CallExpr *C = dyn_cast<CallExpr>(S)) {
151 if (B.succ_begin()[0] != &cfg->getExit()) {
152 HasAbnormalEdge = true;
153 continue;
154 }
155 Expr *CEE = C->getCallee()->IgnoreParenCasts();
156 if (CEE->getType().getNoReturnAttr()) {
157 NoReturnEdge = true;
158 HasFakeEdge = true;
159 } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
160 ValueDecl *VD = DRE->getDecl();
161 if (VD->hasAttr<NoReturnAttr>()) {
162 NoReturnEdge = true;
163 HasFakeEdge = true;
164 }
165 }
166 }
167 // FIXME: Add noreturn message sends.
168 if (NoReturnEdge == false)
169 HasPlainEdge = true;
170 }
171 if (!HasPlainEdge) {
172 if (HasLiveReturn)
173 return NeverFallThrough;
174 return NeverFallThroughOrReturn;
175 }
176 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
177 return MaybeFallThrough;
178 // This says AlwaysFallThrough for calls to functions that are not marked
179 // noreturn, that don't return. If people would like this warning to be more
180 // accurate, such functions should be marked as noreturn.
181 return AlwaysFallThrough;
182}
183
184struct CheckFallThroughDiagnostics {
185 unsigned diag_MaybeFallThrough_HasNoReturn;
186 unsigned diag_MaybeFallThrough_ReturnsNonVoid;
187 unsigned diag_AlwaysFallThrough_HasNoReturn;
188 unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
189 unsigned diag_NeverFallThroughOrReturn;
190 bool funMode;
191
192 static CheckFallThroughDiagnostics MakeForFunction() {
193 CheckFallThroughDiagnostics D;
194 D.diag_MaybeFallThrough_HasNoReturn =
195 diag::warn_falloff_noreturn_function;
196 D.diag_MaybeFallThrough_ReturnsNonVoid =
197 diag::warn_maybe_falloff_nonvoid_function;
198 D.diag_AlwaysFallThrough_HasNoReturn =
199 diag::warn_falloff_noreturn_function;
200 D.diag_AlwaysFallThrough_ReturnsNonVoid =
201 diag::warn_falloff_nonvoid_function;
202 D.diag_NeverFallThroughOrReturn =
203 diag::warn_suggest_noreturn_function;
204 D.funMode = true;
205 return D;
206 }
207
208 static CheckFallThroughDiagnostics MakeForBlock() {
209 CheckFallThroughDiagnostics D;
210 D.diag_MaybeFallThrough_HasNoReturn =
211 diag::err_noreturn_block_has_return_expr;
212 D.diag_MaybeFallThrough_ReturnsNonVoid =
213 diag::err_maybe_falloff_nonvoid_block;
214 D.diag_AlwaysFallThrough_HasNoReturn =
215 diag::err_noreturn_block_has_return_expr;
216 D.diag_AlwaysFallThrough_ReturnsNonVoid =
217 diag::err_falloff_nonvoid_block;
218 D.diag_NeverFallThroughOrReturn =
219 diag::warn_suggest_noreturn_block;
220 D.funMode = false;
221 return D;
222 }
223
224 bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid,
225 bool HasNoReturn) const {
226 if (funMode) {
227 return (D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function)
228 == Diagnostic::Ignored || ReturnsVoid)
229 && (D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr)
230 == Diagnostic::Ignored || !HasNoReturn)
231 && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
232 == Diagnostic::Ignored || !ReturnsVoid);
233 }
234
235 // For blocks.
236 return ReturnsVoid && !HasNoReturn
237 && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
238 == Diagnostic::Ignored || !ReturnsVoid);
239 }
240};
241
242/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a
243/// function that should return a value. Check that we don't fall off the end
244/// of a noreturn function. We assume that functions and blocks not marked
245/// noreturn will return.
246static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
247 QualType BlockTy,
248 const CheckFallThroughDiagnostics& CD,
249 AnalysisContext &AC) {
250
251 bool ReturnsVoid = false;
252 bool HasNoReturn = false;
253
254 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
255 ReturnsVoid = FD->getResultType()->isVoidType();
256 HasNoReturn = FD->hasAttr<NoReturnAttr>() ||
257 FD->getType()->getAs<FunctionType>()->getNoReturnAttr();
258 }
259 else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
260 ReturnsVoid = MD->getResultType()->isVoidType();
261 HasNoReturn = MD->hasAttr<NoReturnAttr>();
262 }
263 else if (isa<BlockDecl>(D)) {
264 if (const FunctionType *FT =
265 BlockTy->getPointeeType()->getAs<FunctionType>()) {
266 if (FT->getResultType()->isVoidType())
267 ReturnsVoid = true;
268 if (FT->getNoReturnAttr())
269 HasNoReturn = true;
270 }
271 }
272
273 Diagnostic &Diags = S.getDiagnostics();
274
275 // Short circuit for compilation speed.
276 if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
277 return;
278
279 // FIXME: Function try block
280 if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
281 switch (CheckFallThrough(AC)) {
282 case MaybeFallThrough:
283 if (HasNoReturn)
284 S.Diag(Compound->getRBracLoc(),
285 CD.diag_MaybeFallThrough_HasNoReturn);
286 else if (!ReturnsVoid)
287 S.Diag(Compound->getRBracLoc(),
288 CD.diag_MaybeFallThrough_ReturnsNonVoid);
289 break;
290 case AlwaysFallThrough:
291 if (HasNoReturn)
292 S.Diag(Compound->getRBracLoc(),
293 CD.diag_AlwaysFallThrough_HasNoReturn);
294 else if (!ReturnsVoid)
295 S.Diag(Compound->getRBracLoc(),
296 CD.diag_AlwaysFallThrough_ReturnsNonVoid);
297 break;
298 case NeverFallThroughOrReturn:
299 if (ReturnsVoid && !HasNoReturn)
300 S.Diag(Compound->getLBracLoc(),
301 CD.diag_NeverFallThroughOrReturn);
302 break;
303 case NeverFallThrough:
304 break;
305 }
306 }
307}
308
309//===----------------------------------------------------------------------===//
310// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based
311// warnings on a function, method, or block.
312//===----------------------------------------------------------------------===//
313
314clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
315 Diagnostic &D = S.getDiagnostics();
316
317 enableCheckFallThrough = 1;
318
319 enableCheckUnreachable = (unsigned)
320 (D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored);
321}
322
323void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D,
324 QualType BlockTy) {
325
326 assert(BlockTy.isNull() || isa<BlockDecl>(D));
327
328 // We avoid doing analysis-based warnings when there are errors for
329 // two reasons:
330 // (1) The CFGs often can't be constructed (if the body is invalid), so
331 // don't bother trying.
332 // (2) The code already has problems; running the analysis just takes more
333 // time.
334 if (S.getDiagnostics().hasErrorOccurred())
335 return;
336
337 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
338 // For function templates, class templates and member function templates
339 // we'll do the analysis at instantiation time.
340 if (FD->isDependentContext())
341 return;
342 }
343
344 const Stmt *Body = D->getBody();
345 assert(Body);
346
347 // Don't generate EH edges for CallExprs as we'd like to avoid the n^2
348 // explosion for destrutors that can result and the compile time hit.
349 AnalysisContext AC(D, false);
350
351 // Warning: check missing 'return'
352 if (enableCheckFallThrough) {
353 const CheckFallThroughDiagnostics &CD =
354 (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
355 : CheckFallThroughDiagnostics::MakeForFunction());
356 CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC);
357 }
358
359 // Warning: check for unreachable code
360 if (enableCheckUnreachable)
361 CheckUnreachable(S, AC);
362}