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         Files((FileSystemOptions())),
43         Sources(Diagnostics, Files),
44         Rewrite(Sources, Options) {
45     Diagnostics.setClient(&DiagnosticPrinter, false);
46   }
47 
~RewriterTestContext()48   ~RewriterTestContext() {}
49 
createInMemoryFile(StringRef Name,StringRef Content)50   FileID createInMemoryFile(StringRef Name, StringRef Content) {
51     std::unique_ptr<llvm::MemoryBuffer> Source =
52         llvm::MemoryBuffer::getMemBuffer(Content);
53     const FileEntry *Entry =
54       Files.getVirtualFile(Name, Source->getBufferSize(), 0);
55     Sources.overrideFileContents(Entry, std::move(Source));
56     assert(Entry != nullptr);
57     return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
58   }
59 
60   // FIXME: this code is mostly a duplicate of
61   // unittests/Tooling/RefactoringTest.cpp. Figure out a way to share it.
createOnDiskFile(StringRef Name,StringRef Content)62   FileID createOnDiskFile(StringRef Name, StringRef Content) {
63     SmallString<1024> Path;
64     int FD;
65     std::error_code EC = llvm::sys::fs::createTemporaryFile(Name, "", FD, Path);
66     assert(!EC);
67     (void)EC;
68 
69     llvm::raw_fd_ostream OutStream(FD, true);
70     OutStream << Content;
71     OutStream.close();
72     const FileEntry *File = Files.getFile(Path);
73     assert(File != nullptr);
74 
75     StringRef Found =
76         TemporaryFiles.insert(std::make_pair(Name, Path.str())).first->second;
77     assert(Found == Path);
78     (void)Found;
79     return Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
80   }
81 
getLocation(FileID ID,unsigned Line,unsigned Column)82   SourceLocation getLocation(FileID ID, unsigned Line, unsigned Column) {
83     SourceLocation Result = Sources.translateFileLineCol(
84         Sources.getFileEntryForID(ID), Line, Column);
85     assert(Result.isValid());
86     return Result;
87   }
88 
getRewrittenText(FileID ID)89   std::string getRewrittenText(FileID ID) {
90     std::string Result;
91     llvm::raw_string_ostream OS(Result);
92     Rewrite.getEditBuffer(ID).write(OS);
93     OS.flush();
94     return Result;
95   }
96 
getFileContentFromDisk(StringRef Name)97   std::string getFileContentFromDisk(StringRef Name) {
98     std::string Path = TemporaryFiles.lookup(Name);
99     assert(!Path.empty());
100     // We need to read directly from the FileManager without relaying through
101     // a FileEntry, as otherwise we'd read through an already opened file
102     // descriptor, which might not see the changes made.
103     // FIXME: Figure out whether there is a way to get the SourceManger to
104     // reopen the file.
105     auto FileBuffer = Files.getBufferForFile(Path);
106     return (*FileBuffer)->getBuffer();
107   }
108 
109   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
110   DiagnosticsEngine Diagnostics;
111   TextDiagnosticPrinter DiagnosticPrinter;
112   FileManager Files;
113   SourceManager Sources;
114   LangOptions Options;
115   Rewriter Rewrite;
116 
117   // Will be set once on disk files are generated.
118   llvm::StringMap<std::string> TemporaryFiles;
119 };
120 
121 } // end namespace clang
122 
123 #endif
124