AnalysisConsumer.cpp revision 223017
1218887Sdim//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
2218887Sdim//
3218887Sdim//                     The LLVM Compiler Infrastructure
4218887Sdim//
5218887Sdim// This file is distributed under the University of Illinois Open Source
6218887Sdim// License. See LICENSE.TXT for details.
7218887Sdim//
8218887Sdim//===----------------------------------------------------------------------===//
9218887Sdim//
10218887Sdim// "Meta" ASTConsumer for running different source analyses.
11218887Sdim//
12218887Sdim//===----------------------------------------------------------------------===//
13218887Sdim
14218887Sdim#include "AnalysisConsumer.h"
15218887Sdim#include "clang/AST/ASTConsumer.h"
16218887Sdim#include "clang/AST/Decl.h"
17218887Sdim#include "clang/AST/DeclCXX.h"
18218887Sdim#include "clang/AST/DeclObjC.h"
19218887Sdim#include "clang/AST/ParentMap.h"
20218887Sdim#include "clang/Analysis/CFG.h"
21218887Sdim#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
22218887Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h"
23218887Sdim#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
24218887Sdim#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
25218887Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
26218887Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
27218887Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
28218887Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
29218887Sdim#include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h"
30218887Sdim
31218887Sdim#include "clang/Basic/FileManager.h"
32218887Sdim#include "clang/Basic/SourceManager.h"
33218887Sdim#include "clang/Frontend/AnalyzerOptions.h"
34218887Sdim#include "clang/Lex/Preprocessor.h"
35218887Sdim#include "llvm/Support/raw_ostream.h"
36218887Sdim#include "llvm/Support/Path.h"
37218887Sdim#include "llvm/Support/Program.h"
38218887Sdim#include "llvm/ADT/OwningPtr.h"
39218887Sdim
40218887Sdimusing namespace clang;
41218887Sdimusing namespace ento;
42218887Sdim
43218887Sdimstatic ExplodedNode::Auditor* CreateUbiViz();
44218887Sdim
45218887Sdim//===----------------------------------------------------------------------===//
46218887Sdim// Special PathDiagnosticClients.
47218887Sdim//===----------------------------------------------------------------------===//
48218887Sdim
49218887Sdimstatic PathDiagnosticClient*
50218887SdimcreatePlistHTMLDiagnosticClient(const std::string& prefix,
51218887Sdim                                const Preprocessor &PP) {
52218887Sdim  PathDiagnosticClient *PD =
53218887Sdim    createHTMLDiagnosticClient(llvm::sys::path::parent_path(prefix), PP);
54218887Sdim  return createPlistDiagnosticClient(prefix, PP, PD);
55218887Sdim}
56218887Sdim
57218887Sdim//===----------------------------------------------------------------------===//
58218887Sdim// AnalysisConsumer declaration.
59218887Sdim//===----------------------------------------------------------------------===//
60218887Sdim
61218887Sdimnamespace {
62218887Sdim
63218887Sdimclass AnalysisConsumer : public ASTConsumer {
64218887Sdimpublic:
65218887Sdim  ASTContext* Ctx;
66218887Sdim  const Preprocessor &PP;
67218887Sdim  const std::string OutDir;
68218887Sdim  AnalyzerOptions Opts;
69218887Sdim
70218887Sdim  // PD is owned by AnalysisManager.
71218887Sdim  PathDiagnosticClient *PD;
72218887Sdim
73218887Sdim  StoreManagerCreator CreateStoreMgr;
74218887Sdim  ConstraintManagerCreator CreateConstraintMgr;
75218887Sdim
76218887Sdim  llvm::OwningPtr<CheckerManager> checkerMgr;
77218887Sdim  llvm::OwningPtr<AnalysisManager> Mgr;
78218887Sdim
79218887Sdim  AnalysisConsumer(const Preprocessor& pp,
80218887Sdim                   const std::string& outdir,
81218887Sdim                   const AnalyzerOptions& opts)
82218887Sdim    : Ctx(0), PP(pp), OutDir(outdir),
83218887Sdim      Opts(opts), PD(0) {
84218887Sdim    DigestAnalyzerOptions();
85218887Sdim  }
86218887Sdim
87218887Sdim  void DigestAnalyzerOptions() {
88218887Sdim    // Create the PathDiagnosticClient.
89218887Sdim    if (!OutDir.empty()) {
90218887Sdim      switch (Opts.AnalysisDiagOpt) {
91218887Sdim      default:
92218887Sdim#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
93218887Sdim        case PD_##NAME: PD = CREATEFN(OutDir, PP); break;
94218887Sdim#include "clang/Frontend/Analyses.def"
95218887Sdim      }
96218887Sdim    } else if (Opts.AnalysisDiagOpt == PD_TEXT) {
97218887Sdim      // Create the text client even without a specified output file since
98218887Sdim      // it just uses diagnostic notes.
99218887Sdim      PD = createTextPathDiagnosticClient("", PP);
100218887Sdim    }
101218887Sdim
102218887Sdim    // Create the analyzer component creators.
103218887Sdim    switch (Opts.AnalysisStoreOpt) {
104218887Sdim    default:
105218887Sdim      assert(0 && "Unknown store manager.");
106218887Sdim#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN)           \
107218887Sdim      case NAME##Model: CreateStoreMgr = CREATEFN; break;
108218887Sdim#include "clang/Frontend/Analyses.def"
109218887Sdim    }
110218887Sdim
111218887Sdim    switch (Opts.AnalysisConstraintsOpt) {
112218887Sdim    default:
113218887Sdim      assert(0 && "Unknown store manager.");
114218887Sdim#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN)     \
115218887Sdim      case NAME##Model: CreateConstraintMgr = CREATEFN; break;
116218887Sdim#include "clang/Frontend/Analyses.def"
117218887Sdim    }
118218887Sdim  }
119218887Sdim
120218887Sdim  void DisplayFunction(const Decl *D) {
121218887Sdim    if (!Opts.AnalyzerDisplayProgress)
122218887Sdim      return;
123218887Sdim
124218887Sdim    SourceManager &SM = Mgr->getASTContext().getSourceManager();
125218887Sdim    PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
126218887Sdim    if (Loc.isValid()) {
127218887Sdim      llvm::errs() << "ANALYZE: " << Loc.getFilename();
128218887Sdim
129218887Sdim      if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
130218887Sdim        const NamedDecl *ND = cast<NamedDecl>(D);
131218887Sdim        llvm::errs() << ' ' << ND << '\n';
132218887Sdim      }
133218887Sdim      else if (isa<BlockDecl>(D)) {
134218887Sdim        llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
135218887Sdim                     << Loc.getColumn() << '\n';
136218887Sdim      }
137218887Sdim      else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
138218887Sdim        Selector S = MD->getSelector();
139218887Sdim        llvm::errs() << ' ' << S.getAsString();
140218887Sdim      }
141218887Sdim    }
142218887Sdim  }
143218887Sdim
144218887Sdim  virtual void Initialize(ASTContext &Context) {
145218887Sdim    Ctx = &Context;
146219077Sdim    checkerMgr.reset(registerCheckers(Opts, PP.getLangOptions(),
147219077Sdim                                      PP.getDiagnostics()));
148218887Sdim    Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
149218887Sdim                                  PP.getLangOptions(), PD,
150218887Sdim                                  CreateStoreMgr, CreateConstraintMgr,
151218887Sdim                                  checkerMgr.get(),
152218887Sdim                                  /* Indexer */ 0,
153218887Sdim                                  Opts.MaxNodes, Opts.MaxLoop,
154218887Sdim                                  Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
155218887Sdim                                  Opts.PurgeDead, Opts.EagerlyAssume,
156218887Sdim                                  Opts.TrimGraph, Opts.InlineCall,
157218887Sdim                                  Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
158218887Sdim                                  Opts.CFGAddInitializers,
159218887Sdim                                  Opts.EagerlyTrimEGraph));
160218887Sdim  }
161218887Sdim
162218887Sdim  virtual void HandleTranslationUnit(ASTContext &C);
163218887Sdim  void HandleDeclContext(ASTContext &C, DeclContext *dc);
164218887Sdim
165221345Sdim  void HandleCode(Decl *D);
166218887Sdim};
167218887Sdim} // end anonymous namespace
168218887Sdim
169218887Sdim//===----------------------------------------------------------------------===//
170218887Sdim// AnalysisConsumer implementation.
171218887Sdim//===----------------------------------------------------------------------===//
172218887Sdim
173218887Sdimvoid AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) {
174218887Sdim  BugReporter BR(*Mgr);
175218887Sdim  for (DeclContext::decl_iterator I = dc->decls_begin(), E = dc->decls_end();
176218887Sdim       I != E; ++I) {
177218887Sdim    Decl *D = *I;
178218887Sdim    checkerMgr->runCheckersOnASTDecl(D, *Mgr, BR);
179218887Sdim
180218887Sdim    switch (D->getKind()) {
181218887Sdim      case Decl::Namespace: {
182218887Sdim        HandleDeclContext(C, cast<NamespaceDecl>(D));
183218887Sdim        break;
184218887Sdim      }
185218887Sdim      case Decl::CXXConstructor:
186218887Sdim      case Decl::CXXDestructor:
187218887Sdim      case Decl::CXXConversion:
188218887Sdim      case Decl::CXXMethod:
189218887Sdim      case Decl::Function: {
190218887Sdim        FunctionDecl* FD = cast<FunctionDecl>(D);
191218887Sdim        // We skip function template definitions, as their semantics is
192218887Sdim        // only determined when they are instantiated.
193218887Sdim        if (FD->isThisDeclarationADefinition() &&
194218887Sdim            !FD->isDependentContext()) {
195218887Sdim          if (!Opts.AnalyzeSpecificFunction.empty() &&
196218887Sdim              FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
197218887Sdim            break;
198218887Sdim          DisplayFunction(FD);
199221345Sdim          HandleCode(FD);
200218887Sdim        }
201218887Sdim        break;
202218887Sdim      }
203223017Sdim
204223017Sdim      case Decl::ObjCCategoryImpl:
205218887Sdim      case Decl::ObjCImplementation: {
206223017Sdim        ObjCImplDecl* ID = cast<ObjCImplDecl>(*I);
207221345Sdim        HandleCode(ID);
208218887Sdim
209223017Sdim        for (ObjCContainerDecl::method_iterator MI = ID->meth_begin(),
210218887Sdim             ME = ID->meth_end(); MI != ME; ++MI) {
211221345Sdim          checkerMgr->runCheckersOnASTDecl(*MI, *Mgr, BR);
212221345Sdim
213218887Sdim          if ((*MI)->isThisDeclarationADefinition()) {
214218887Sdim            if (!Opts.AnalyzeSpecificFunction.empty() &&
215223017Sdim                Opts.AnalyzeSpecificFunction !=
216223017Sdim                  (*MI)->getSelector().getAsString())
217218887Sdim              break;
218218887Sdim            DisplayFunction(*MI);
219221345Sdim            HandleCode(*MI);
220218887Sdim          }
221218887Sdim        }
222218887Sdim        break;
223218887Sdim      }
224218887Sdim
225218887Sdim      default:
226218887Sdim        break;
227218887Sdim    }
228218887Sdim  }
229218887Sdim}
230218887Sdim
231218887Sdimvoid AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
232218887Sdim  BugReporter BR(*Mgr);
233218887Sdim  TranslationUnitDecl *TU = C.getTranslationUnitDecl();
234218887Sdim  checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
235218887Sdim  HandleDeclContext(C, TU);
236218887Sdim
237223017Sdim  // After all decls handled, run checkers on the entire TranslationUnit.
238223017Sdim  checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
239223017Sdim
240218887Sdim  // Explicitly destroy the PathDiagnosticClient.  This will flush its output.
241218887Sdim  // FIXME: This should be replaced with something that doesn't rely on
242218887Sdim  // side-effects in PathDiagnosticClient's destructor. This is required when
243218887Sdim  // used with option -disable-free.
244218887Sdim  Mgr.reset(NULL);
245218887Sdim}
246218887Sdim
247218887Sdimstatic void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) {
248218887Sdim  if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
249218887Sdim    WL.push_back(BD);
250218887Sdim
251218887Sdim  for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
252218887Sdim       I!=E; ++I)
253218887Sdim    if (DeclContext *DC = dyn_cast<DeclContext>(*I))
254218887Sdim      FindBlocks(DC, WL);
255218887Sdim}
256218887Sdim
257221345Sdimstatic void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
258221345Sdim                                 Decl *D);
259218887Sdim
260221345Sdimvoid AnalysisConsumer::HandleCode(Decl *D) {
261221345Sdim
262221345Sdim  // Don't run the actions if an error has occurred with parsing the file.
263218887Sdim  Diagnostic &Diags = PP.getDiagnostics();
264218887Sdim  if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
265218887Sdim    return;
266218887Sdim
267218887Sdim  // Don't run the actions on declarations in header files unless
268218887Sdim  // otherwise specified.
269218887Sdim  SourceManager &SM = Ctx->getSourceManager();
270218887Sdim  SourceLocation SL = SM.getInstantiationLoc(D->getLocation());
271218887Sdim  if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL))
272218887Sdim    return;
273218887Sdim
274218887Sdim  // Clear the AnalysisManager of old AnalysisContexts.
275218887Sdim  Mgr->ClearContexts();
276218887Sdim
277218887Sdim  // Dispatch on the actions.
278218887Sdim  llvm::SmallVector<Decl*, 10> WL;
279218887Sdim  WL.push_back(D);
280218887Sdim
281218887Sdim  if (D->hasBody() && Opts.AnalyzeNestedBlocks)
282218887Sdim    FindBlocks(cast<DeclContext>(D), WL);
283218887Sdim
284218887Sdim  BugReporter BR(*Mgr);
285218887Sdim  for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
286218887Sdim       WI != WE; ++WI)
287221345Sdim    if ((*WI)->hasBody()) {
288218887Sdim      checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
289221345Sdim      if (checkerMgr->hasPathSensitiveCheckers())
290221345Sdim        ActionObjCMemChecker(*this, *Mgr, *WI);
291221345Sdim    }
292218887Sdim}
293218887Sdim
294218887Sdim//===----------------------------------------------------------------------===//
295221345Sdim// Path-sensitive checking.
296218887Sdim//===----------------------------------------------------------------------===//
297218887Sdim
298218887Sdimstatic void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
299218887Sdim                               Decl *D,
300218887Sdim                               TransferFuncs* tf) {
301218887Sdim
302218887Sdim  llvm::OwningPtr<TransferFuncs> TF(tf);
303218887Sdim
304218887Sdim  // Construct the analysis engine.  We first query for the LiveVariables
305218887Sdim  // information to see if the CFG is valid.
306218887Sdim  // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
307218887Sdim  if (!mgr.getLiveVariables(D))
308218887Sdim    return;
309218887Sdim  ExprEngine Eng(mgr, TF.take());
310218887Sdim
311218887Sdim  // Set the graph auditor.
312218887Sdim  llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
313218887Sdim  if (mgr.shouldVisualizeUbigraph()) {
314218887Sdim    Auditor.reset(CreateUbiViz());
315218887Sdim    ExplodedNode::SetAuditor(Auditor.get());
316218887Sdim  }
317218887Sdim
318218887Sdim  // Execute the worklist algorithm.
319218887Sdim  Eng.ExecuteWorkList(mgr.getStackFrame(D, 0), mgr.getMaxNodes());
320218887Sdim
321218887Sdim  // Release the auditor (if any) so that it doesn't monitor the graph
322218887Sdim  // created BugReporter.
323218887Sdim  ExplodedNode::SetAuditor(0);
324218887Sdim
325218887Sdim  // Visualize the exploded graph.
326218887Sdim  if (mgr.shouldVisualizeGraphviz())
327218887Sdim    Eng.ViewGraph(mgr.shouldTrimGraph());
328218887Sdim
329218887Sdim  // Display warnings.
330218887Sdim  Eng.getBugReporter().FlushReports();
331218887Sdim}
332218887Sdim
333218887Sdimstatic void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr,
334218887Sdim                                  Decl *D, bool GCEnabled) {
335218887Sdim
336218887Sdim  TransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(),
337218887Sdim                                         GCEnabled,
338218887Sdim                                         mgr.getLangOptions());
339218887Sdim
340218887Sdim  ActionExprEngine(C, mgr, D, TF);
341218887Sdim}
342218887Sdim
343218887Sdimstatic void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
344218887Sdim                               Decl *D) {
345218887Sdim
346218887Sdim switch (mgr.getLangOptions().getGCMode()) {
347218887Sdim default:
348218887Sdim   assert (false && "Invalid GC mode.");
349218887Sdim case LangOptions::NonGC:
350218887Sdim   ActionObjCMemCheckerAux(C, mgr, D, false);
351218887Sdim   break;
352218887Sdim
353218887Sdim case LangOptions::GCOnly:
354218887Sdim   ActionObjCMemCheckerAux(C, mgr, D, true);
355218887Sdim   break;
356218887Sdim
357218887Sdim case LangOptions::HybridGC:
358218887Sdim   ActionObjCMemCheckerAux(C, mgr, D, false);
359218887Sdim   ActionObjCMemCheckerAux(C, mgr, D, true);
360218887Sdim   break;
361218887Sdim }
362218887Sdim}
363218887Sdim
364218887Sdim//===----------------------------------------------------------------------===//
365218887Sdim// AnalysisConsumer creation.
366218887Sdim//===----------------------------------------------------------------------===//
367218887Sdim
368218887SdimASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
369218887Sdim                                           const std::string& OutDir,
370218887Sdim                                           const AnalyzerOptions& Opts) {
371218887Sdim  llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts));
372218887Sdim
373218887Sdim  // Last, disable the effects of '-Werror' when using the AnalysisConsumer.
374218887Sdim  pp.getDiagnostics().setWarningsAsErrors(false);
375218887Sdim
376218887Sdim  return C.take();
377218887Sdim}
378218887Sdim
379218887Sdim//===----------------------------------------------------------------------===//
380218887Sdim// Ubigraph Visualization.  FIXME: Move to separate file.
381218887Sdim//===----------------------------------------------------------------------===//
382218887Sdim
383218887Sdimnamespace {
384218887Sdim
385218887Sdimclass UbigraphViz : public ExplodedNode::Auditor {
386218887Sdim  llvm::OwningPtr<llvm::raw_ostream> Out;
387218887Sdim  llvm::sys::Path Dir, Filename;
388218887Sdim  unsigned Cntr;
389218887Sdim
390218887Sdim  typedef llvm::DenseMap<void*,unsigned> VMap;
391218887Sdim  VMap M;
392218887Sdim
393218887Sdimpublic:
394218887Sdim  UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
395218887Sdim              llvm::sys::Path& filename);
396218887Sdim
397218887Sdim  ~UbigraphViz();
398218887Sdim
399218887Sdim  virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst);
400218887Sdim};
401218887Sdim
402218887Sdim} // end anonymous namespace
403218887Sdim
404218887Sdimstatic ExplodedNode::Auditor* CreateUbiViz() {
405218887Sdim  std::string ErrMsg;
406218887Sdim
407218887Sdim  llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
408218887Sdim  if (!ErrMsg.empty())
409218887Sdim    return 0;
410218887Sdim
411218887Sdim  llvm::sys::Path Filename = Dir;
412218887Sdim  Filename.appendComponent("llvm_ubi");
413218887Sdim  Filename.makeUnique(true,&ErrMsg);
414218887Sdim
415218887Sdim  if (!ErrMsg.empty())
416218887Sdim    return 0;
417218887Sdim
418218887Sdim  llvm::errs() << "Writing '" << Filename.str() << "'.\n";
419218887Sdim
420218887Sdim  llvm::OwningPtr<llvm::raw_fd_ostream> Stream;
421218887Sdim  Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg));
422218887Sdim
423218887Sdim  if (!ErrMsg.empty())
424218887Sdim    return 0;
425218887Sdim
426218887Sdim  return new UbigraphViz(Stream.take(), Dir, Filename);
427218887Sdim}
428218887Sdim
429218887Sdimvoid UbigraphViz::AddEdge(ExplodedNode* Src, ExplodedNode* Dst) {
430218887Sdim
431218887Sdim  assert (Src != Dst && "Self-edges are not allowed.");
432218887Sdim
433218887Sdim  // Lookup the Src.  If it is a new node, it's a root.
434218887Sdim  VMap::iterator SrcI= M.find(Src);
435218887Sdim  unsigned SrcID;
436218887Sdim
437218887Sdim  if (SrcI == M.end()) {
438218887Sdim    M[Src] = SrcID = Cntr++;
439218887Sdim    *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
440218887Sdim  }
441218887Sdim  else
442218887Sdim    SrcID = SrcI->second;
443218887Sdim
444218887Sdim  // Lookup the Dst.
445218887Sdim  VMap::iterator DstI= M.find(Dst);
446218887Sdim  unsigned DstID;
447218887Sdim
448218887Sdim  if (DstI == M.end()) {
449218887Sdim    M[Dst] = DstID = Cntr++;
450218887Sdim    *Out << "('vertex', " << DstID << ")\n";
451218887Sdim  }
452218887Sdim  else {
453218887Sdim    // We have hit DstID before.  Change its style to reflect a cache hit.
454218887Sdim    DstID = DstI->second;
455218887Sdim    *Out << "('change_vertex_style', " << DstID << ", 1)\n";
456218887Sdim  }
457218887Sdim
458218887Sdim  // Add the edge.
459218887Sdim  *Out << "('edge', " << SrcID << ", " << DstID
460218887Sdim       << ", ('arrow','true'), ('oriented', 'true'))\n";
461218887Sdim}
462218887Sdim
463218887SdimUbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
464218887Sdim                         llvm::sys::Path& filename)
465218887Sdim  : Out(out), Dir(dir), Filename(filename), Cntr(0) {
466218887Sdim
467218887Sdim  *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
468218887Sdim  *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
469218887Sdim          " ('size', '1.5'))\n";
470218887Sdim}
471218887Sdim
472218887SdimUbigraphViz::~UbigraphViz() {
473218887Sdim  Out.reset(0);
474218887Sdim  llvm::errs() << "Running 'ubiviz' program... ";
475218887Sdim  std::string ErrMsg;
476218887Sdim  llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz");
477218887Sdim  std::vector<const char*> args;
478218887Sdim  args.push_back(Ubiviz.c_str());
479218887Sdim  args.push_back(Filename.c_str());
480218887Sdim  args.push_back(0);
481218887Sdim
482218887Sdim  if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) {
483218887Sdim    llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
484218887Sdim  }
485218887Sdim
486218887Sdim  // Delete the directory.
487218887Sdim  Dir.eraseFromDisk(true);
488218887Sdim}
489