Manuel, I don't think it is compatible to Win32. Manipulating opened files would be hard on Win32. 2012/05/23 2:05 "Manuel Klimek" <[email protected]>:
> Author: klimek > Date: Tue May 22 12:01:35 2012 > New Revision: 157260 > > URL: http://llvm.org/viewvc/llvm-project?rev=157260&view=rev > Log: > Adds a method overwriteChangedFiles to the Rewriter. This is implemented by > first writing the changed files to a temporary location and then > overwriting > the original files atomically. > > Also adds a RewriterTestContext to aid unit testing rewrting logic in > general. > > > Added: > cfe/trunk/unittests/Tooling/RewriterTest.cpp (with props) > cfe/trunk/unittests/Tooling/RewriterTestContext.h (with props) > Modified: > cfe/trunk/include/clang/Rewrite/Rewriter.h > cfe/trunk/lib/Rewrite/Rewriter.cpp > cfe/trunk/unittests/CMakeLists.txt > > Modified: cfe/trunk/include/clang/Rewrite/Rewriter.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Rewrite/Rewriter.h?rev=157260&r1=157259&r2=157260&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Rewrite/Rewriter.h (original) > +++ cfe/trunk/include/clang/Rewrite/Rewriter.h Tue May 22 12:01:35 2012 > @@ -279,6 +279,13 @@ > buffer_iterator buffer_begin() { return RewriteBuffers.begin(); } > buffer_iterator buffer_end() { return RewriteBuffers.end(); } > > + /// SaveFiles - Save all changed files to disk. > + /// > + /// Returns whether not all changes were saved successfully. > + /// Outputs diagnostics via the source manager's diagnostic engine > + /// in case of an error. > + bool overwriteChangedFiles(); > + > private: > unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) > const; > }; > > Modified: cfe/trunk/lib/Rewrite/Rewriter.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Rewrite/Rewriter.cpp?rev=157260&r1=157259&r2=157260&view=diff > > ============================================================================== > --- cfe/trunk/lib/Rewrite/Rewriter.cpp (original) > +++ cfe/trunk/lib/Rewrite/Rewriter.cpp Tue May 22 12:01:35 2012 > @@ -15,9 +15,12 @@ > #include "clang/Rewrite/Rewriter.h" > #include "clang/AST/Stmt.h" > #include "clang/AST/Decl.h" > -#include "clang/Lex/Lexer.h" > +#include "clang/Basic/DiagnosticIDs.h" > +#include "clang/Basic/FileManager.h" > #include "clang/Basic/SourceManager.h" > +#include "clang/Lex/Lexer.h" > #include "llvm/ADT/SmallString.h" > +#include "llvm/Support/FileSystem.h" > using namespace clang; > > raw_ostream &RewriteBuffer::write(raw_ostream &os) const { > @@ -412,3 +415,68 @@ > > return false; > } > + > +// A wrapper for a file stream that atomically overwrites the target. > +// > +// Creates a file output stream for a temporary file in the constructor, > +// which is later accessible via getStream() if ok() return true. > +// Flushes the stream and moves the temporary file to the target location > +// in the destructor. > +class AtomicallyMovedFile { > +public: > + AtomicallyMovedFile(DiagnosticsEngine &Diagnostics, StringRef Filename, > + bool &AllWritten) > + : Diagnostics(Diagnostics), Filename(Filename), > AllWritten(AllWritten) { > + TempFilename = Filename; > + TempFilename += "-%%%%%%%%"; > + int FD; > + if (llvm::sys::fs::unique_file(TempFilename.str(), FD, TempFilename, > + /*makeAbsolute=*/true, 0664)) { > + AllWritten = false; > + Diagnostics.Report(clang::diag::err_unable_to_make_temp) > + << TempFilename; > + } else { > + FileStream.reset(new llvm::raw_fd_ostream(FD, > /*shouldClose=*/true)); > + } > + } > + > + ~AtomicallyMovedFile() { > + if (!ok()) return; > + > + FileStream->flush(); > + if (llvm::error_code ec = > + llvm::sys::fs::rename(TempFilename.str(), Filename)) { > + AllWritten = false; > + Diagnostics.Report(clang::diag::err_unable_to_rename_temp) > + << TempFilename << Filename << ec.message(); > + bool existed; > + // If the remove fails, there's not a lot we can do - this is > already an > + // error. > + llvm::sys::fs::remove(TempFilename.str(), existed); > + } > + } > + > + bool ok() { return FileStream; } > + llvm::raw_ostream &getStream() { return *FileStream; } > + > +private: > + DiagnosticsEngine &Diagnostics; > + StringRef Filename; > + SmallString<128> TempFilename; > + OwningPtr<llvm::raw_fd_ostream> FileStream; > + bool &AllWritten; > +}; > + > +bool Rewriter::overwriteChangedFiles() { > + bool AllWritten = true; > + for (buffer_iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) > { > + const FileEntry *Entry = > + getSourceMgr().getFileEntryForID(I->first); > + AtomicallyMovedFile File(getSourceMgr().getDiagnostics(), > Entry->getName(), > + AllWritten); > + if (File.ok()) { > + I->second.write(File.getStream()); > + } > + } > + return !AllWritten; > +} > > Modified: cfe/trunk/unittests/CMakeLists.txt > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/CMakeLists.txt?rev=157260&r1=157259&r2=157260&view=diff > > ============================================================================== > --- cfe/trunk/unittests/CMakeLists.txt (original) > +++ cfe/trunk/unittests/CMakeLists.txt Tue May 22 12:01:35 2012 > @@ -70,5 +70,6 @@ > Tooling/CompilationDatabaseTest.cpp > Tooling/ToolingTest.cpp > Tooling/RecursiveASTVisitorTest.cpp > - USED_LIBS gtest gtest_main clangAST clangTooling > + Tooling/RewriterTest.cpp > + USED_LIBS gtest gtest_main clangAST clangTooling clangRewrite > ) > > Added: cfe/trunk/unittests/Tooling/RewriterTest.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/RewriterTest.cpp?rev=157260&view=auto > > ============================================================================== > --- cfe/trunk/unittests/Tooling/RewriterTest.cpp (added) > +++ cfe/trunk/unittests/Tooling/RewriterTest.cpp Tue May 22 12:01:35 2012 > @@ -0,0 +1,37 @@ > +//===- unittest/Tooling/RewriterTest.cpp > ----------------------------------===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > > +//===----------------------------------------------------------------------===// > + > +#include "RewriterTestContext.h" > +#include "gtest/gtest.h" > + > +namespace clang { > + > +TEST(Rewriter, OverwritesChangedFiles) { > + RewriterTestContext Context; > + FileID ID = Context.createOnDiskFile("t.cpp", > "line1\nline2\nline3\nline4"); > + Context.Rewrite.ReplaceText(Context.getLocation(ID, 2, 1), 5, > "replaced"); > + EXPECT_FALSE(Context.Rewrite.overwriteChangedFiles()); > + EXPECT_EQ("line1\nreplaced\nline3\nline4", > + Context.getFileContentFromDisk("t.cpp")); > +} > + > +TEST(Rewriter, ContinuesOverwritingFilesOnError) { > + RewriterTestContext Context; > + FileID FailingID = Context.createInMemoryFile("invalid/failing.cpp", > "test"); > + Context.Rewrite.ReplaceText(Context.getLocation(FailingID, 1, 2), 1, > "other"); > + FileID WorkingID = Context.createOnDiskFile( > + "working.cpp", "line1\nline2\nline3\nline4"); > + Context.Rewrite.ReplaceText(Context.getLocation(WorkingID, 2, 1), 5, > + "replaced"); > + EXPECT_TRUE(Context.Rewrite.overwriteChangedFiles()); > + EXPECT_EQ("line1\nreplaced\nline3\nline4", > + Context.getFileContentFromDisk("working.cpp")); > +} > + > +} // end namespace clang > > Propchange: cfe/trunk/unittests/Tooling/RewriterTest.cpp > > ------------------------------------------------------------------------------ > svn:eol-style = LF > > Added: cfe/trunk/unittests/Tooling/RewriterTestContext.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/RewriterTestContext.h?rev=157260&view=auto > > ============================================================================== > --- cfe/trunk/unittests/Tooling/RewriterTestContext.h (added) > +++ cfe/trunk/unittests/Tooling/RewriterTestContext.h Tue May 22 12:01:35 > 2012 > @@ -0,0 +1,120 @@ > +//===--- RewriterTestContext.h ----------------------------------*- C++ > -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > > +//===----------------------------------------------------------------------===// > +// > +// This file defines a utility class for Rewriter related tests. > +// > > +//===----------------------------------------------------------------------===// > + > +#ifndef LLVM_CLANG_REWRITER_TEST_CONTEXT_H > +#define LLVM_CLANG_REWRITER_TEST_CONTEXT_H > + > +#include "clang/Basic/Diagnostic.h" > +#include "clang/Basic/FileManager.h" > +#include "clang/Basic/LangOptions.h" > +#include "clang/Basic/SourceManager.h" > +#include "clang/Frontend/DiagnosticOptions.h" > +#include "clang/Frontend/TextDiagnosticPrinter.h" > +#include "clang/Rewrite/Rewriter.h" > +#include "llvm/Support/Path.h" > +#include "llvm/Support/raw_ostream.h" > + > +namespace clang { > + > +/// \brief A class that sets up a ready to use Rewriter. > +/// > +/// Useful in unit tests that need a Rewriter. Creates all dependencies > +/// of a Rewriter with default values for testing and provides convenience > +/// methods, which help with writing tests that change files. > +class RewriterTestContext { > + public: > + RewriterTestContext() > + : Diagnostics(llvm::IntrusiveRefCntPtr<DiagnosticIDs>()), > + DiagnosticPrinter(llvm::outs(), DiagnosticOptions()), > + Files((FileSystemOptions())), > + Sources(Diagnostics, Files), > + Rewrite(Sources, Options) { > + Diagnostics.setClient(&DiagnosticPrinter, false); > + } > + > + ~RewriterTestContext() { > + if (TemporaryDirectory.isValid()) { > + std::string ErrorInfo; > + TemporaryDirectory.eraseFromDisk(true, &ErrorInfo); > + assert(ErrorInfo.empty()); > + } > + } > + > + FileID createInMemoryFile(StringRef Name, StringRef Content) { > + const llvm::MemoryBuffer *Source = > + llvm::MemoryBuffer::getMemBuffer(Content); > + const FileEntry *Entry = > + Files.getVirtualFile(Name, Source->getBufferSize(), 0); > + Sources.overrideFileContents(Entry, Source, true); > + assert(Entry != NULL); > + return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User); > + } > + > + FileID createOnDiskFile(StringRef Name, StringRef Content) { > + if (!TemporaryDirectory.isValid()) { > + std::string ErrorInfo; > + TemporaryDirectory = > llvm::sys::Path::GetTemporaryDirectory(&ErrorInfo); > + assert(ErrorInfo.empty()); > + } > + llvm::SmallString<1024> Path(TemporaryDirectory.str()); > + llvm::sys::path::append(Path, Name); > + std::string ErrorInfo; > + llvm::raw_fd_ostream OutStream(Path.c_str(), > + ErrorInfo, > llvm::raw_fd_ostream::F_Binary); > + assert(ErrorInfo.empty()); > + OutStream << Content; > + OutStream.close(); > + const FileEntry *File = Files.getFile(Path); > + assert(File != NULL); > + return Sources.createFileID(File, SourceLocation(), SrcMgr::C_User); > + } > + > + SourceLocation getLocation(FileID ID, unsigned Line, unsigned Column) { > + SourceLocation Result = Sources.translateFileLineCol( > + Sources.getFileEntryForID(ID), Line, Column); > + assert(Result.isValid()); > + return Result; > + } > + > + std::string getRewrittenText(FileID ID) { > + std::string Result; > + llvm::raw_string_ostream OS(Result); > + Rewrite.getEditBuffer(ID).write(OS); > + return Result; > + } > + > + std::string getFileContentFromDisk(StringRef Name) { > + llvm::SmallString<1024> Path(TemporaryDirectory.str()); > + llvm::sys::path::append(Path, Name); > + // We need to read directly from the FileManager without relaying > through > + // a FileEntry, as otherwise we'd read through an already opened file > + // descriptor, which might not see the changes made. > + // FIXME: Figure out whether there is a way to get the SourceManger to > + // reopen the file. > + return Files.getBufferForFile(Path, NULL)->getBuffer(); > + } > + > + DiagnosticsEngine Diagnostics; > + TextDiagnosticPrinter DiagnosticPrinter; > + FileManager Files; > + SourceManager Sources; > + LangOptions Options; > + Rewriter Rewrite; > + > + // Will be set once on disk files are generated. > + llvm::sys::Path TemporaryDirectory; > +}; > + > +} // end namespace clang > + > +#endif > > Propchange: cfe/trunk/unittests/Tooling/RewriterTestContext.h > > ------------------------------------------------------------------------------ > svn:eol-style = LF > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
