AnalysisConsumer.cpp revision 43dee220252ef0b42c5f8a3bb1eca97f84f2565f
1//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
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// "Meta" ASTConsumer for running different source analyses.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AnalysisConsumer.h"
15#include "clang/AST/ASTConsumer.h"
16#include "clang/AST/Decl.h"
17#include "clang/AST/DeclCXX.h"
18#include "clang/AST/DeclObjC.h"
19#include "clang/AST/ParentMap.h"
20#include "clang/Analysis/Analyses/LiveVariables.h"
21#include "clang/Analysis/Analyses/UninitializedValues.h"
22#include "clang/Analysis/CFG.h"
23#include "clang/StaticAnalyzer/Core/CheckerManager.h"
24#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
25#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
26#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
27#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
28#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
29#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
30#include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h"
31
32// FIXME: Restructure checker registration.
33#include "../Checkers/ExperimentalChecks.h"
34#include "../Checkers/InternalChecks.h"
35
36#include "clang/Basic/FileManager.h"
37#include "clang/Basic/SourceManager.h"
38#include "clang/Frontend/AnalyzerOptions.h"
39#include "clang/Lex/Preprocessor.h"
40#include "llvm/Support/raw_ostream.h"
41#include "llvm/Support/Path.h"
42#include "llvm/Support/Program.h"
43#include "llvm/ADT/OwningPtr.h"
44
45using namespace clang;
46using namespace ento;
47
48static ExplodedNode::Auditor* CreateUbiViz();
49
50//===----------------------------------------------------------------------===//
51// Special PathDiagnosticClients.
52//===----------------------------------------------------------------------===//
53
54static PathDiagnosticClient*
55createPlistHTMLDiagnosticClient(const std::string& prefix,
56                                const Preprocessor &PP) {
57  PathDiagnosticClient *PD =
58    createHTMLDiagnosticClient(llvm::sys::path::parent_path(prefix), PP);
59  return createPlistDiagnosticClient(prefix, PP, PD);
60}
61
62//===----------------------------------------------------------------------===//
63// AnalysisConsumer declaration.
64//===----------------------------------------------------------------------===//
65
66namespace {
67
68class AnalysisConsumer : public ASTConsumer {
69public:
70  typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D);
71  typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M,
72                           TranslationUnitDecl &TU);
73
74private:
75  typedef std::vector<CodeAction> Actions;
76  typedef std::vector<TUAction> TUActions;
77
78  Actions FunctionActions;
79  Actions ObjCMethodActions;
80  Actions ObjCImplementationActions;
81  Actions CXXMethodActions;
82  TUActions TranslationUnitActions; // Remove this.
83
84public:
85  ASTContext* Ctx;
86  const Preprocessor &PP;
87  const std::string OutDir;
88  AnalyzerOptions Opts;
89
90  // PD is owned by AnalysisManager.
91  PathDiagnosticClient *PD;
92
93  StoreManagerCreator CreateStoreMgr;
94  ConstraintManagerCreator CreateConstraintMgr;
95
96  llvm::OwningPtr<CheckerManager> checkerMgr;
97  llvm::OwningPtr<AnalysisManager> Mgr;
98
99  AnalysisConsumer(const Preprocessor& pp,
100                   const std::string& outdir,
101                   const AnalyzerOptions& opts)
102    : Ctx(0), PP(pp), OutDir(outdir),
103      Opts(opts), PD(0) {
104    DigestAnalyzerOptions();
105  }
106
107  void DigestAnalyzerOptions() {
108    // Create the PathDiagnosticClient.
109    if (!OutDir.empty()) {
110      switch (Opts.AnalysisDiagOpt) {
111      default:
112#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
113        case PD_##NAME: PD = CREATEFN(OutDir, PP); break;
114#include "clang/Frontend/Analyses.def"
115      }
116    } else if (Opts.AnalysisDiagOpt == PD_TEXT) {
117      // Create the text client even without a specified output file since
118      // it just uses diagnostic notes.
119      PD = createTextPathDiagnosticClient("", PP);
120    }
121
122    // Create the analyzer component creators.
123    switch (Opts.AnalysisStoreOpt) {
124    default:
125      assert(0 && "Unknown store manager.");
126#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN)           \
127      case NAME##Model: CreateStoreMgr = CREATEFN; break;
128#include "clang/Frontend/Analyses.def"
129    }
130
131    switch (Opts.AnalysisConstraintsOpt) {
132    default:
133      assert(0 && "Unknown store manager.");
134#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN)     \
135      case NAME##Model: CreateConstraintMgr = CREATEFN; break;
136#include "clang/Frontend/Analyses.def"
137    }
138  }
139
140  void DisplayFunction(const Decl *D) {
141    if (!Opts.AnalyzerDisplayProgress)
142      return;
143
144    SourceManager &SM = Mgr->getASTContext().getSourceManager();
145    PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
146    if (Loc.isValid()) {
147      llvm::errs() << "ANALYZE: " << Loc.getFilename();
148
149      if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
150        const NamedDecl *ND = cast<NamedDecl>(D);
151        llvm::errs() << ' ' << ND << '\n';
152      }
153      else if (isa<BlockDecl>(D)) {
154        llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
155                     << Loc.getColumn() << '\n';
156      }
157      else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
158        Selector S = MD->getSelector();
159        llvm::errs() << ' ' << S.getAsString();
160      }
161    }
162  }
163
164  void addCodeAction(CodeAction action) {
165    FunctionActions.push_back(action);
166    ObjCMethodActions.push_back(action);
167    CXXMethodActions.push_back(action);
168  }
169
170  void addTranslationUnitAction(TUAction action) {
171    TranslationUnitActions.push_back(action);
172  }
173
174  void addObjCImplementationAction(CodeAction action) {
175    ObjCImplementationActions.push_back(action);
176  }
177
178  virtual void Initialize(ASTContext &Context) {
179    Ctx = &Context;
180    checkerMgr.reset(registerCheckers(Opts, PP.getDiagnostics()));
181    Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
182                                  PP.getLangOptions(), PD,
183                                  CreateStoreMgr, CreateConstraintMgr,
184                                  checkerMgr.get(),
185                                  /* Indexer */ 0,
186                                  Opts.MaxNodes, Opts.MaxLoop,
187                                  Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
188                                  Opts.PurgeDead, Opts.EagerlyAssume,
189                                  Opts.TrimGraph, Opts.InlineCall,
190                                  Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
191                                  Opts.CFGAddInitializers,
192                                  Opts.EagerlyTrimEGraph));
193  }
194
195  virtual void HandleTranslationUnit(ASTContext &C);
196  void HandleDeclContext(ASTContext &C, DeclContext *dc);
197
198  void HandleCode(Decl *D, Actions& actions);
199};
200} // end anonymous namespace
201
202//===----------------------------------------------------------------------===//
203// AnalysisConsumer implementation.
204//===----------------------------------------------------------------------===//
205
206void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) {
207  for (DeclContext::decl_iterator I = dc->decls_begin(), E = dc->decls_end();
208       I != E; ++I) {
209    Decl *D = *I;
210
211    switch (D->getKind()) {
212      case Decl::Namespace: {
213        HandleDeclContext(C, cast<NamespaceDecl>(D));
214        break;
215      }
216      case Decl::CXXConstructor:
217      case Decl::CXXDestructor:
218      case Decl::CXXConversion:
219      case Decl::CXXMethod:
220      case Decl::Function: {
221        FunctionDecl* FD = cast<FunctionDecl>(D);
222        // We skip function template definitions, as their semantics is
223        // only determined when they are instantiated.
224        if (FD->isThisDeclarationADefinition() &&
225            !FD->isDependentContext()) {
226          if (!Opts.AnalyzeSpecificFunction.empty() &&
227              FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
228            break;
229          DisplayFunction(FD);
230          HandleCode(FD, FunctionActions);
231        }
232        break;
233      }
234
235      case Decl::ObjCImplementation: {
236        ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I);
237        HandleCode(ID, ObjCImplementationActions);
238
239        for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(),
240             ME = ID->meth_end(); MI != ME; ++MI) {
241          if ((*MI)->isThisDeclarationADefinition()) {
242            if (!Opts.AnalyzeSpecificFunction.empty() &&
243                Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString())
244              break;
245            DisplayFunction(*MI);
246            HandleCode(*MI, ObjCMethodActions);
247          }
248        }
249        break;
250      }
251
252      default:
253        break;
254    }
255  }
256}
257
258void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
259  TranslationUnitDecl *TU = C.getTranslationUnitDecl();
260  HandleDeclContext(C, TU);
261
262  for (TUActions::iterator I = TranslationUnitActions.begin(),
263                           E = TranslationUnitActions.end(); I != E; ++I) {
264    (*I)(*this, *Mgr, *TU);
265  }
266
267  // Explicitly destroy the PathDiagnosticClient.  This will flush its output.
268  // FIXME: This should be replaced with something that doesn't rely on
269  // side-effects in PathDiagnosticClient's destructor. This is required when
270  // used with option -disable-free.
271  Mgr.reset(NULL);
272}
273
274static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) {
275  if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
276    WL.push_back(BD);
277
278  for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
279       I!=E; ++I)
280    if (DeclContext *DC = dyn_cast<DeclContext>(*I))
281      FindBlocks(DC, WL);
282}
283
284void AnalysisConsumer::HandleCode(Decl *D, Actions& actions) {
285
286  // Don't run the actions if an error has occured with parsing the file.
287  Diagnostic &Diags = PP.getDiagnostics();
288  if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
289    return;
290
291  // Don't run the actions on declarations in header files unless
292  // otherwise specified.
293  SourceManager &SM = Ctx->getSourceManager();
294  SourceLocation SL = SM.getInstantiationLoc(D->getLocation());
295  if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL))
296    return;
297
298  // Clear the AnalysisManager of old AnalysisContexts.
299  Mgr->ClearContexts();
300
301  // Dispatch on the actions.
302  llvm::SmallVector<Decl*, 10> WL;
303  WL.push_back(D);
304
305  if (D->hasBody() && Opts.AnalyzeNestedBlocks)
306    FindBlocks(cast<DeclContext>(D), WL);
307
308  for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
309    for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
310         WI != WE; ++WI)
311      (*I)(*this, *Mgr, *WI);
312}
313
314//===----------------------------------------------------------------------===//
315// Analyses
316//===----------------------------------------------------------------------===//
317
318static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr,
319                                 Decl *D) {
320  if (LiveVariables *L = mgr.getLiveVariables(D)) {
321    BugReporter BR(mgr);
322    CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR);
323  }
324}
325
326static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr,
327                                 Decl *D) {
328  if (CFG* c = mgr.getCFG(D)) {
329    CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic());
330  }
331}
332
333
334static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
335                               Decl *D,
336                               TransferFuncs* tf) {
337
338  llvm::OwningPtr<TransferFuncs> TF(tf);
339
340  // Construct the analysis engine.  We first query for the LiveVariables
341  // information to see if the CFG is valid.
342  // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
343  if (!mgr.getLiveVariables(D))
344    return;
345  ExprEngine Eng(mgr, TF.take());
346
347  if (C.Opts.EnableExperimentalInternalChecks)
348    RegisterExperimentalInternalChecks(Eng);
349
350  RegisterAppleChecks(Eng, *D);
351
352  if (C.Opts.EnableExperimentalChecks)
353    RegisterExperimentalChecks(Eng);
354
355  if (C.Opts.ObjCSelfInitCheck && isa<ObjCMethodDecl>(D))
356    registerObjCSelfInitChecker(Eng);
357
358  // Enable idempotent operation checking if it was explicitly turned on, or if
359  // we are running experimental checks (i.e. everything)
360  if (C.Opts.IdempotentOps || C.Opts.EnableExperimentalChecks
361      || C.Opts.EnableExperimentalInternalChecks)
362    RegisterIdempotentOperationChecker(Eng);
363
364  if (C.Opts.BufferOverflows)
365    RegisterArrayBoundCheckerV2(Eng);
366
367  // Enable AnalyzerStatsChecker if it was given as an argument
368  if (C.Opts.AnalyzerStats)
369    RegisterAnalyzerStatsChecker(Eng);
370
371  // Set the graph auditor.
372  llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
373  if (mgr.shouldVisualizeUbigraph()) {
374    Auditor.reset(CreateUbiViz());
375    ExplodedNode::SetAuditor(Auditor.get());
376  }
377
378  // Execute the worklist algorithm.
379  Eng.ExecuteWorkList(mgr.getStackFrame(D, 0), mgr.getMaxNodes());
380
381  // Release the auditor (if any) so that it doesn't monitor the graph
382  // created BugReporter.
383  ExplodedNode::SetAuditor(0);
384
385  // Visualize the exploded graph.
386  if (mgr.shouldVisualizeGraphviz())
387    Eng.ViewGraph(mgr.shouldTrimGraph());
388
389  // Display warnings.
390  Eng.getBugReporter().FlushReports();
391}
392
393static void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr,
394                                  Decl *D, bool GCEnabled) {
395
396  TransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(),
397                                         GCEnabled,
398                                         mgr.getLangOptions());
399
400  ActionExprEngine(C, mgr, D, TF);
401}
402
403static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
404                               Decl *D) {
405
406 switch (mgr.getLangOptions().getGCMode()) {
407 default:
408   assert (false && "Invalid GC mode.");
409 case LangOptions::NonGC:
410   ActionObjCMemCheckerAux(C, mgr, D, false);
411   break;
412
413 case LangOptions::GCOnly:
414   ActionObjCMemCheckerAux(C, mgr, D, true);
415   break;
416
417 case LangOptions::HybridGC:
418   ActionObjCMemCheckerAux(C, mgr, D, false);
419   ActionObjCMemCheckerAux(C, mgr, D, true);
420   break;
421 }
422}
423
424static void ActionDisplayLiveVariables(AnalysisConsumer &C,
425                                       AnalysisManager& mgr, Decl *D) {
426  if (LiveVariables* L = mgr.getLiveVariables(D)) {
427    L->dumpBlockLiveness(mgr.getSourceManager());
428  }
429}
430
431static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
432  if (CFG *cfg = mgr.getCFG(D)) {
433    cfg->dump(mgr.getLangOptions());
434  }
435}
436
437static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
438  if (CFG *cfg = mgr.getCFG(D)) {
439    cfg->viewCFG(mgr.getLangOptions());
440  }
441}
442
443static void ActionSecuritySyntacticChecks(AnalysisConsumer &C,
444                                          AnalysisManager &mgr, Decl *D) {
445  BugReporter BR(mgr);
446  CheckSecuritySyntaxOnly(D, BR);
447}
448
449static void ActionLLVMConventionChecker(AnalysisConsumer &C,
450                                        AnalysisManager &mgr,
451                                        TranslationUnitDecl &TU) {
452  BugReporter BR(mgr);
453  CheckLLVMConventions(TU, BR);
454}
455
456static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr,
457                                  Decl *D) {
458  if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
459    return;
460  BugReporter BR(mgr);
461  CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR);
462}
463
464static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr,
465                                      Decl *D) {
466  BugReporter BR(mgr);
467  CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR);
468}
469
470static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr,
471                                   Decl *D) {
472  BugReporter BR(mgr);
473  CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR);
474}
475
476static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr,
477                                    Decl *D) {
478  BugReporter BR(mgr);
479  CheckSizeofPointer(D, BR);
480}
481
482//===----------------------------------------------------------------------===//
483// AnalysisConsumer creation.
484//===----------------------------------------------------------------------===//
485
486ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
487                                           const std::string& OutDir,
488                                           const AnalyzerOptions& Opts) {
489  llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts));
490
491  for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i)
492    switch (Opts.AnalysisList[i]) {
493#define ANALYSIS(NAME, CMD, DESC, SCOPE)\
494    case NAME:\
495      C->add ## SCOPE ## Action(&Action ## NAME);\
496      break;
497#include "clang/Frontend/Analyses.def"
498    default: break;
499    }
500
501  // Last, disable the effects of '-Werror' when using the AnalysisConsumer.
502  pp.getDiagnostics().setWarningsAsErrors(false);
503
504  return C.take();
505}
506
507//===----------------------------------------------------------------------===//
508// Ubigraph Visualization.  FIXME: Move to separate file.
509//===----------------------------------------------------------------------===//
510
511namespace {
512
513class UbigraphViz : public ExplodedNode::Auditor {
514  llvm::OwningPtr<llvm::raw_ostream> Out;
515  llvm::sys::Path Dir, Filename;
516  unsigned Cntr;
517
518  typedef llvm::DenseMap<void*,unsigned> VMap;
519  VMap M;
520
521public:
522  UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
523              llvm::sys::Path& filename);
524
525  ~UbigraphViz();
526
527  virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst);
528};
529
530} // end anonymous namespace
531
532static ExplodedNode::Auditor* CreateUbiViz() {
533  std::string ErrMsg;
534
535  llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
536  if (!ErrMsg.empty())
537    return 0;
538
539  llvm::sys::Path Filename = Dir;
540  Filename.appendComponent("llvm_ubi");
541  Filename.makeUnique(true,&ErrMsg);
542
543  if (!ErrMsg.empty())
544    return 0;
545
546  llvm::errs() << "Writing '" << Filename.str() << "'.\n";
547
548  llvm::OwningPtr<llvm::raw_fd_ostream> Stream;
549  Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg));
550
551  if (!ErrMsg.empty())
552    return 0;
553
554  return new UbigraphViz(Stream.take(), Dir, Filename);
555}
556
557void UbigraphViz::AddEdge(ExplodedNode* Src, ExplodedNode* Dst) {
558
559  assert (Src != Dst && "Self-edges are not allowed.");
560
561  // Lookup the Src.  If it is a new node, it's a root.
562  VMap::iterator SrcI= M.find(Src);
563  unsigned SrcID;
564
565  if (SrcI == M.end()) {
566    M[Src] = SrcID = Cntr++;
567    *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
568  }
569  else
570    SrcID = SrcI->second;
571
572  // Lookup the Dst.
573  VMap::iterator DstI= M.find(Dst);
574  unsigned DstID;
575
576  if (DstI == M.end()) {
577    M[Dst] = DstID = Cntr++;
578    *Out << "('vertex', " << DstID << ")\n";
579  }
580  else {
581    // We have hit DstID before.  Change its style to reflect a cache hit.
582    DstID = DstI->second;
583    *Out << "('change_vertex_style', " << DstID << ", 1)\n";
584  }
585
586  // Add the edge.
587  *Out << "('edge', " << SrcID << ", " << DstID
588       << ", ('arrow','true'), ('oriented', 'true'))\n";
589}
590
591UbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
592                         llvm::sys::Path& filename)
593  : Out(out), Dir(dir), Filename(filename), Cntr(0) {
594
595  *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
596  *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
597          " ('size', '1.5'))\n";
598}
599
600UbigraphViz::~UbigraphViz() {
601  Out.reset(0);
602  llvm::errs() << "Running 'ubiviz' program... ";
603  std::string ErrMsg;
604  llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz");
605  std::vector<const char*> args;
606  args.push_back(Ubiviz.c_str());
607  args.push_back(Filename.c_str());
608  args.push_back(0);
609
610  if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) {
611    llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
612  }
613
614  // Delete the directory.
615  Dir.eraseFromDisk(true);
616}
617