Move AnalysisConsumer.h and Analyses.def from tools/clang-cc to 
include/clang/Frontend, and move AnalysisConsumer.cpp from 
tools/clang-cc to lib/Frontend.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72135 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
new file mode 100644
index 0000000..02a8710
--- /dev/null
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -0,0 +1,659 @@
+//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// "Meta" ASTConsumer for running different source analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/AnalysisConsumer.h"
+#include "clang/Frontend/PathDiagnosticClients.h"
+#include "clang/Frontend/ManagerRegistry.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "clang/AST/CFG.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include "llvm/System/Program.h"
+
+using namespace clang;
+
+static ExplodedNodeImpl::Auditor* CreateUbiViz();
+
+//===----------------------------------------------------------------------===//
+// Basic type definitions.
+//===----------------------------------------------------------------------===//
+
+namespace {  
+  class AnalysisManager;
+  typedef void (*CodeAction)(AnalysisManager& Mgr);
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer declaration.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+  class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
+    typedef std::vector<CodeAction> Actions;
+    Actions FunctionActions;
+    Actions ObjCMethodActions;
+    Actions ObjCImplementationActions;
+    Actions TranslationUnitActions;
+    
+  public:
+    const LangOptions& LOpts;    
+    Diagnostic &Diags;
+    ASTContext* Ctx;
+    Preprocessor* PP;
+    PreprocessorFactory* PPF;
+    const std::string OutDir;
+    AnalyzerOptions Opts;
+    llvm::OwningPtr<PathDiagnosticClient> PD;
+
+    AnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
+                     PreprocessorFactory* ppf,
+                     const LangOptions& lopts,
+                     const std::string& outdir,
+                     const AnalyzerOptions& opts)
+      : LOpts(lopts), Diags(diags),
+        Ctx(0), PP(pp), PPF(ppf),
+        OutDir(outdir), Opts(opts) {}
+    
+    void addCodeAction(CodeAction action) {
+      FunctionActions.push_back(action);
+      ObjCMethodActions.push_back(action);
+    }
+    
+    void addObjCImplementationAction(CodeAction action) {
+      ObjCImplementationActions.push_back(action);
+    }
+    
+    void addTranslationUnitAction(CodeAction action) {
+      TranslationUnitActions.push_back(action);
+    }
+    
+    virtual void Initialize(ASTContext &Context) {
+      Ctx = &Context;
+    }
+    
+    virtual void HandleTopLevelDecl(DeclGroupRef D) {
+      for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
+        HandleTopLevelSingleDecl(*I);
+    }
+    
+    void HandleTopLevelSingleDecl(Decl *D);
+    virtual void HandleTranslationUnit(ASTContext &C);
+    
+    void HandleCode(Decl* D, Stmt* Body, Actions& actions);
+  };
+    
+  
+  class VISIBILITY_HIDDEN AnalysisManager : public BugReporterData {
+    Decl* D; Stmt* Body; 
+    
+    enum AnalysisScope { ScopeTU, ScopeDecl } AScope;
+      
+    AnalysisConsumer& C;
+    bool DisplayedFunction;
+    
+    llvm::OwningPtr<CFG> cfg;
+    llvm::OwningPtr<LiveVariables> liveness;
+    llvm::OwningPtr<ParentMap> PM;
+
+    // Configurable components creators.
+    StoreManagerCreator CreateStoreMgr;
+    ConstraintManagerCreator CreateConstraintMgr;
+
+  public:
+    AnalysisManager(AnalysisConsumer& c, Decl* d, Stmt* b, bool displayProgress) 
+      : D(d), Body(b), AScope(ScopeDecl), C(c), 
+        DisplayedFunction(!displayProgress) {
+      setManagerCreators();
+    }
+    
+    AnalysisManager(AnalysisConsumer& c, bool displayProgress) 
+      : D(0), Body(0), AScope(ScopeTU), C(c),
+        DisplayedFunction(!displayProgress) {
+      setManagerCreators();
+    }
+    
+    Decl* getCodeDecl() const { 
+      assert (AScope == ScopeDecl);
+      return D;
+    }
+    
+    Stmt* getBody() const {
+      assert (AScope == ScopeDecl);
+      return Body;
+    }
+    
+    StoreManagerCreator getStoreManagerCreator() {
+      return CreateStoreMgr;
+    };
+
+    ConstraintManagerCreator getConstraintManagerCreator() {
+      return CreateConstraintMgr;
+    }
+    
+    virtual CFG* getCFG() {
+      if (!cfg) cfg.reset(CFG::buildCFG(getBody()));
+      return cfg.get();
+    }
+    
+    virtual ParentMap& getParentMap() {
+      if (!PM) 
+        PM.reset(new ParentMap(getBody()));
+      return *PM.get();
+    }
+    
+    virtual ASTContext& getContext() {
+      return *C.Ctx;
+    }
+    
+    virtual SourceManager& getSourceManager() {
+      return getContext().getSourceManager();
+    }
+    
+    virtual Diagnostic& getDiagnostic() {
+      return C.Diags;
+    }
+    
+    const LangOptions& getLangOptions() const {
+      return C.LOpts;
+    }
+    
+    virtual PathDiagnosticClient* getPathDiagnosticClient() {
+      if (C.PD.get() == 0 && !C.OutDir.empty()) {
+        switch (C.Opts.AnalysisDiagOpt) {
+          default:
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE)\
+case PD_##NAME: C.PD.reset(CREATEFN(C.OutDir, C.PP, C.PPF)); break;
+#include "Analyses.def"
+        }
+      }
+      return C.PD.get();      
+    }
+      
+    virtual LiveVariables* getLiveVariables() {
+      if (!liveness) {
+        CFG* c = getCFG();
+        if (!c) return 0;
+        
+        liveness.reset(new LiveVariables(getContext(), *c));
+        liveness->runOnCFG(*c);
+        liveness->runOnAllBlocks(*c, 0, true);
+      }
+      
+      return liveness.get();
+    }
+    
+    bool shouldVisualizeGraphviz() const { return C.Opts.VisualizeEGDot; }
+
+    bool shouldVisualizeUbigraph() const { return C.Opts.VisualizeEGUbi; }
+
+    bool shouldVisualize() const {
+      return C.Opts.VisualizeEGDot || C.Opts.VisualizeEGUbi;
+    }
+
+    bool shouldTrimGraph() const { return C.Opts.TrimGraph; }
+
+    bool shouldPurgeDead() const { return C.Opts.PurgeDead; }
+
+    bool shouldEagerlyAssume() const { return C.Opts.EagerlyAssume; }
+
+    void DisplayFunction() {
+      
+      if (DisplayedFunction)
+        return;
+      
+      DisplayedFunction = true;
+      
+      // FIXME: Is getCodeDecl() always a named decl?
+      if (isa<FunctionDecl>(getCodeDecl()) ||
+          isa<ObjCMethodDecl>(getCodeDecl())) {
+        NamedDecl *ND = cast<NamedDecl>(getCodeDecl());
+        SourceManager &SM = getContext().getSourceManager();
+        llvm::cerr << "ANALYZE: "
+          << SM.getPresumedLoc(ND->getLocation()).getFilename()
+          << ' ' << ND->getNameAsString() << '\n';
+      }
+    }
+
+  private:
+    /// Set configurable analyzer components creators. First check if there are
+    /// components registered at runtime. Otherwise fall back to builtin
+    /// components.
+    void setManagerCreators() {
+      if (ManagerRegistry::StoreMgrCreator != 0) {
+        CreateStoreMgr = ManagerRegistry::StoreMgrCreator;
+      }
+      else {
+        switch (C.Opts.AnalysisStoreOpt) {
+        default:
+          assert(0 && "Unknown store manager.");
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN)     \
+          case NAME##Model: CreateStoreMgr = CREATEFN; break;
+#include "Analyses.def"
+        }
+      }
+
+      if (ManagerRegistry::ConstraintMgrCreator != 0)
+        CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator;
+      else {
+        switch (C.Opts.AnalysisConstraintsOpt) {
+        default:
+          assert(0 && "Unknown store manager.");
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN)     \
+          case NAME##Model: CreateConstraintMgr = CREATEFN; break;
+#include "Analyses.def"
+        }
+      }
+
+      
+      // Some DiagnosticClients should be created all the time instead of
+      // lazily.  Create those now.
+      switch (C.Opts.AnalysisDiagOpt) {
+        default: break;
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE)\
+case PD_##NAME: if (AUTOCREATE) getPathDiagnosticClient(); break;
+#include "Analyses.def"
+      }      
+    }
+
+  };
+
+} // end anonymous namespace
+
+namespace llvm {
+  template <> struct FoldingSetTrait<CodeAction> {
+    static inline void Profile(CodeAction X, FoldingSetNodeID& ID) {
+      ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
+    }
+  };   
+}
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer implementation.
+//===----------------------------------------------------------------------===//
+
+void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) { 
+  switch (D->getKind()) {
+    case Decl::Function: {
+      FunctionDecl* FD = cast<FunctionDecl>(D);
+
+      if (Opts.AnalyzeSpecificFunction.size() > 0 && 
+          Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName())
+        break;
+      
+      Stmt* Body = FD->getBody(*Ctx);
+      if (Body) HandleCode(FD, Body, FunctionActions);
+      break;
+    }
+      
+    case Decl::ObjCMethod: {
+      ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
+      
+      if (Opts.AnalyzeSpecificFunction.size() > 0 &&
+          Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString())
+        return;
+      
+      Stmt* Body = MD->getBody();
+      if (Body) HandleCode(MD, Body, ObjCMethodActions);
+      break;
+    }
+      
+    default:
+      break;
+  }
+}
+
+void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
+
+  if(!TranslationUnitActions.empty()) {
+    AnalysisManager mgr(*this, Opts.AnalyzerDisplayProgress);
+    for (Actions::iterator I = TranslationUnitActions.begin(), 
+         E = TranslationUnitActions.end(); I != E; ++I)
+      (*I)(mgr);  
+  }
+
+  if (!ObjCImplementationActions.empty()) {
+    TranslationUnitDecl *TUD = C.getTranslationUnitDecl();
+    
+    for (DeclContext::decl_iterator I = TUD->decls_begin(C),
+                                    E = TUD->decls_end(C);
+         I != E; ++I)
+      if (ObjCImplementationDecl* ID = dyn_cast<ObjCImplementationDecl>(*I))
+        HandleCode(ID, 0, ObjCImplementationActions);
+  }
+  
+  // Delete the PathDiagnosticClient here just in case the AnalysisConsumer
+  // object doesn't get released.  This will cause any side-effects in the
+  // destructor of the PathDiagnosticClient to get executed.
+  PD.reset();
+}
+
+void AnalysisConsumer::HandleCode(Decl* D, Stmt* Body, Actions& actions) {
+  
+  // Don't run the actions if an error has occured with parsing the file.
+  if (Diags.hasErrorOccurred())
+    return;
+
+  // Don't run the actions on declarations in header files unless
+  // otherwise specified.
+  if (!Opts.AnalyzeAll &&
+      !Ctx->getSourceManager().isFromMainFile(D->getLocation()))
+    return;  
+
+  // Create an AnalysisManager that will manage the state for analyzing
+  // this method/function.
+  AnalysisManager mgr(*this, D, Body, Opts.AnalyzerDisplayProgress);
+  
+  // Dispatch on the actions.  
+  for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
+    (*I)(mgr);  
+}
+
+//===----------------------------------------------------------------------===//
+// Analyses
+//===----------------------------------------------------------------------===//
+
+static void ActionWarnDeadStores(AnalysisManager& mgr) {
+  if (LiveVariables* L = mgr.getLiveVariables()) {
+    BugReporter BR(mgr);
+    CheckDeadStores(*L, BR);
+  }
+}
+
+static void ActionWarnUninitVals(AnalysisManager& mgr) {
+  if (CFG* c = mgr.getCFG())
+    CheckUninitializedValues(*c, mgr.getContext(), mgr.getDiagnostic());
+}
+
+
+static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf,
+                               bool StandardWarnings = true) {
+  
+  
+  llvm::OwningPtr<GRTransferFuncs> TF(tf);
+
+  // Display progress.
+  mgr.DisplayFunction();
+
+  // Construct the analysis engine.
+  LiveVariables* L = mgr.getLiveVariables();
+  if (!L) return;
+
+  GRExprEngine Eng(*mgr.getCFG(), *mgr.getCodeDecl(), mgr.getContext(), *L, mgr,
+                   mgr.shouldPurgeDead(), mgr.shouldEagerlyAssume(),
+                   mgr.getStoreManagerCreator(), 
+                   mgr.getConstraintManagerCreator());
+
+  Eng.setTransferFunctions(tf);
+  
+  if (StandardWarnings) {
+    Eng.RegisterInternalChecks();
+    RegisterAppleChecks(Eng);
+  }
+
+  // Set the graph auditor.
+  llvm::OwningPtr<ExplodedNodeImpl::Auditor> Auditor;
+  if (mgr.shouldVisualizeUbigraph()) {
+    Auditor.reset(CreateUbiViz());
+    ExplodedNodeImpl::SetAuditor(Auditor.get());
+  }
+  
+  // Execute the worklist algorithm.
+  Eng.ExecuteWorkList();
+  
+  // Release the auditor (if any) so that it doesn't monitor the graph
+  // created BugReporter.
+  ExplodedNodeImpl::SetAuditor(0);
+
+  // Visualize the exploded graph.
+  if (mgr.shouldVisualizeGraphviz())
+    Eng.ViewGraph(mgr.shouldTrimGraph());
+  
+  // Display warnings.
+  Eng.getBugReporter().FlushReports();
+}
+
+static void ActionCheckerCFRefAux(AnalysisManager& mgr, bool GCEnabled,
+                                  bool StandardWarnings) {
+  
+  GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getContext(),
+                                         GCEnabled,
+                                         mgr.getLangOptions());
+    
+  ActionGRExprEngine(mgr, TF, StandardWarnings);
+}
+
+static void ActionCheckerCFRef(AnalysisManager& mgr) {
+     
+ switch (mgr.getLangOptions().getGCMode()) {
+   default:
+     assert (false && "Invalid GC mode.");
+   case LangOptions::NonGC:
+     ActionCheckerCFRefAux(mgr, false, true);
+     break;
+    
+   case LangOptions::GCOnly:
+     ActionCheckerCFRefAux(mgr, true, true);
+     break;
+     
+   case LangOptions::HybridGC:
+     ActionCheckerCFRefAux(mgr, false, true);
+     ActionCheckerCFRefAux(mgr, true, false);
+     break;
+ }
+}
+
+static void ActionCheckerSimple(AnalysisManager& mgr) {
+  ActionGRExprEngine(mgr, MakeGRSimpleValsTF());
+}
+
+static void ActionDisplayLiveVariables(AnalysisManager& mgr) {
+  if (LiveVariables* L = mgr.getLiveVariables()) {
+    mgr.DisplayFunction();  
+    L->dumpBlockLiveness(mgr.getSourceManager());
+  }
+}
+
+static void ActionCFGDump(AnalysisManager& mgr) {
+  if (CFG* c = mgr.getCFG()) {
+    mgr.DisplayFunction();
+    c->dump();
+  }
+}
+
+static void ActionCFGView(AnalysisManager& mgr) {
+  if (CFG* c = mgr.getCFG()) {
+    mgr.DisplayFunction();
+    c->viewCFG();  
+  }
+}
+
+static void ActionWarnObjCDealloc(AnalysisManager& mgr) {
+  if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
+    return;
+      
+  BugReporter BR(mgr);
+  
+  CheckObjCDealloc(cast<ObjCImplementationDecl>(mgr.getCodeDecl()), 
+                   mgr.getLangOptions(), BR);  
+}
+
+static void ActionWarnObjCUnusedIvars(AnalysisManager& mgr) {
+  BugReporter BR(mgr);
+  CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(mgr.getCodeDecl()), BR);  
+}
+
+static void ActionWarnObjCMethSigs(AnalysisManager& mgr) {
+  BugReporter BR(mgr);
+  
+  CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(mgr.getCodeDecl()),
+                             BR);
+}
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer creation.
+//===----------------------------------------------------------------------===//
+
+ASTConsumer* clang::CreateAnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
+                                           PreprocessorFactory* ppf,
+                                           const LangOptions& lopts,
+                                           const std::string& OutDir,
+                                           const AnalyzerOptions& Opts) {
+
+  llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(diags, pp, ppf,
+                                                           lopts, OutDir,
+                                                           Opts));
+
+  for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i)
+    switch (Opts.AnalysisList[i]) {
+#define ANALYSIS(NAME, CMD, DESC, SCOPE)\
+      case NAME:\
+        C->add ## SCOPE ## Action(&Action ## NAME);\
+        break;
+#include "Analyses.def"
+      default: break;
+    }
+  
+  // Last, disable the effects of '-Werror' when using the AnalysisConsumer.
+  diags.setWarningsAsErrors(false);
+
+  return C.take();
+}
+
+//===----------------------------------------------------------------------===//
+// Ubigraph Visualization.  FIXME: Move to separate file.
+//===----------------------------------------------------------------------===//
+
+namespace {
+  
+class UbigraphViz : public ExplodedNodeImpl::Auditor {
+  llvm::OwningPtr<llvm::raw_ostream> Out;
+  llvm::sys::Path Dir, Filename;
+  unsigned Cntr;
+
+  typedef llvm::DenseMap<void*,unsigned> VMap;
+  VMap M;
+  
+public:
+  UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
+              llvm::sys::Path& filename);
+  
+  ~UbigraphViz();
+  
+  virtual void AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst);  
+};
+  
+} // end anonymous namespace
+
+static ExplodedNodeImpl::Auditor* CreateUbiViz() {
+  std::string ErrMsg;
+  
+  llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
+  if (!ErrMsg.empty())
+    return 0;
+
+  llvm::sys::Path Filename = Dir;
+  Filename.appendComponent("llvm_ubi");
+  Filename.makeUnique(true,&ErrMsg);
+
+  if (!ErrMsg.empty())
+    return 0;
+
+  llvm::cerr << "Writing '" << Filename << "'.\n";
+  
+  llvm::OwningPtr<llvm::raw_fd_ostream> Stream;
+  std::string filename = Filename.toString();
+  Stream.reset(new llvm::raw_fd_ostream(filename.c_str(), false, ErrMsg));
+
+  if (!ErrMsg.empty())
+    return 0;
+  
+  return new UbigraphViz(Stream.take(), Dir, Filename);
+}
+
+void UbigraphViz::AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst) {
+  
+  assert (Src != Dst && "Self-edges are not allowed.");
+  
+  // Lookup the Src.  If it is a new node, it's a root.
+  VMap::iterator SrcI= M.find(Src);
+  unsigned SrcID;
+  
+  if (SrcI == M.end()) {
+    M[Src] = SrcID = Cntr++;
+    *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
+  }
+  else
+    SrcID = SrcI->second;
+  
+  // Lookup the Dst.
+  VMap::iterator DstI= M.find(Dst);
+  unsigned DstID;
+
+  if (DstI == M.end()) {
+    M[Dst] = DstID = Cntr++;
+    *Out << "('vertex', " << DstID << ")\n";
+  }
+  else {
+    // We have hit DstID before.  Change its style to reflect a cache hit.
+    DstID = DstI->second;
+    *Out << "('change_vertex_style', " << DstID << ", 1)\n";
+  }
+
+  // Add the edge.
+  *Out << "('edge', " << SrcID << ", " << DstID 
+       << ", ('arrow','true'), ('oriented', 'true'))\n";
+}
+
+UbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
+                         llvm::sys::Path& filename)
+  : Out(out), Dir(dir), Filename(filename), Cntr(0) {
+
+  *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
+  *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
+          " ('size', '1.5'))\n";
+}
+
+UbigraphViz::~UbigraphViz() {
+  Out.reset(0);
+  llvm::cerr << "Running 'ubiviz' program... ";
+  std::string ErrMsg;
+  llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz");
+  std::vector<const char*> args;
+  args.push_back(Ubiviz.c_str());
+  args.push_back(Filename.c_str());
+  args.push_back(0);
+  
+  if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) {
+    llvm::cerr << "Error viewing graph: " << ErrMsg << "\n";
+  }
+  
+  // Delete the directory.
+  Dir.eraseFromDisk(true); 
+}