1 //===--- RewriterTestContext.h ----------------------------------*- 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 a utility class for Rewriter related tests. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_UNITTESTS_TOOLING_REWRITERTESTCONTEXT_H 15 #define LLVM_CLANG_UNITTESTS_TOOLING_REWRITERTESTCONTEXT_H 16 17 #include "clang/Basic/Diagnostic.h" 18 #include "clang/Basic/DiagnosticOptions.h" 19 #include "clang/Basic/FileManager.h" 20 #include "clang/Basic/LangOptions.h" 21 #include "clang/Basic/SourceManager.h" 22 #include "clang/Frontend/TextDiagnosticPrinter.h" 23 #include "clang/Rewrite/Core/Rewriter.h" 24 #include "llvm/Support/FileSystem.h" 25 #include "llvm/Support/Path.h" 26 #include "llvm/Support/raw_ostream.h" 27 28 namespace clang { 29 30 /// \brief A class that sets up a ready to use Rewriter. 31 /// 32 /// Useful in unit tests that need a Rewriter. Creates all dependencies 33 /// of a Rewriter with default values for testing and provides convenience 34 /// methods, which help with writing tests that change files. 35 class RewriterTestContext { 36 public: RewriterTestContext()37 RewriterTestContext() 38 : DiagOpts(new DiagnosticOptions()), 39 Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), 40 &*DiagOpts), 41 DiagnosticPrinter(llvm::outs(), &*DiagOpts), 42 InMemoryFileSystem(new vfs::InMemoryFileSystem), 43 OverlayFileSystem( 44 new vfs::OverlayFileSystem(vfs::getRealFileSystem())), 45 Files(FileSystemOptions(), OverlayFileSystem), 46 Sources(Diagnostics, Files), Rewrite(Sources, Options) { 47 Diagnostics.setClient(&DiagnosticPrinter, false); 48 // FIXME: To make these tests truly in-memory, we need to overlay the 49 // builtin headers. 50 OverlayFileSystem->pushOverlay(InMemoryFileSystem); 51 } 52 ~RewriterTestContext()53 ~RewriterTestContext() {} 54 createInMemoryFile(StringRef Name,StringRef Content)55 FileID createInMemoryFile(StringRef Name, StringRef Content) { 56 std::unique_ptr<llvm::MemoryBuffer> Source = 57 llvm::MemoryBuffer::getMemBuffer(Content); 58 InMemoryFileSystem->addFile(Name, 0, std::move(Source)); 59 60 const FileEntry *Entry = Files.getFile(Name); 61 assert(Entry != nullptr); 62 return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User); 63 } 64 65 // FIXME: this code is mostly a duplicate of 66 // unittests/Tooling/RefactoringTest.cpp. Figure out a way to share it. createOnDiskFile(StringRef Name,StringRef Content)67 FileID createOnDiskFile(StringRef Name, StringRef Content) { 68 SmallString<1024> Path; 69 int FD; 70 std::error_code EC = llvm::sys::fs::createTemporaryFile(Name, "", FD, Path); 71 assert(!EC); 72 (void)EC; 73 74 llvm::raw_fd_ostream OutStream(FD, true); 75 OutStream << Content; 76 OutStream.close(); 77 const FileEntry *File = Files.getFile(Path); 78 assert(File != nullptr); 79 80 StringRef Found = 81 TemporaryFiles.insert(std::make_pair(Name, Path.str())).first->second; 82 assert(Found == Path); 83 (void)Found; 84 return Sources.createFileID(File, SourceLocation(), SrcMgr::C_User); 85 } 86 getLocation(FileID ID,unsigned Line,unsigned Column)87 SourceLocation getLocation(FileID ID, unsigned Line, unsigned Column) { 88 SourceLocation Result = Sources.translateFileLineCol( 89 Sources.getFileEntryForID(ID), Line, Column); 90 assert(Result.isValid()); 91 return Result; 92 } 93 getRewrittenText(FileID ID)94 std::string getRewrittenText(FileID ID) { 95 std::string Result; 96 llvm::raw_string_ostream OS(Result); 97 Rewrite.getEditBuffer(ID).write(OS); 98 OS.flush(); 99 return Result; 100 } 101 getFileContentFromDisk(StringRef Name)102 std::string getFileContentFromDisk(StringRef Name) { 103 std::string Path = TemporaryFiles.lookup(Name); 104 assert(!Path.empty()); 105 // We need to read directly from the FileManager without relaying through 106 // a FileEntry, as otherwise we'd read through an already opened file 107 // descriptor, which might not see the changes made. 108 // FIXME: Figure out whether there is a way to get the SourceManger to 109 // reopen the file. 110 auto FileBuffer = Files.getBufferForFile(Path); 111 return (*FileBuffer)->getBuffer(); 112 } 113 114 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; 115 DiagnosticsEngine Diagnostics; 116 TextDiagnosticPrinter DiagnosticPrinter; 117 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem; 118 IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFileSystem; 119 FileManager Files; 120 SourceManager Sources; 121 LangOptions Options; 122 Rewriter Rewrite; 123 124 // Will be set once on disk files are generated. 125 llvm::StringMap<std::string> TemporaryFiles; 126 }; 127 128 } // end namespace clang 129 130 #endif 131