1bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek//===--- RewriterTestContext.h ----------------------------------*- C++ -*-===//
2bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek//
3bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek//                     The LLVM Compiler Infrastructure
4bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek//
5bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// This file is distributed under the University of Illinois Open Source
6bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// License. See LICENSE.TXT for details.
7bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek//
8bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek//===----------------------------------------------------------------------===//
9bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek//
10bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek//  This file defines a utility class for Rewriter related tests.
11bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek//
12bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek//===----------------------------------------------------------------------===//
13bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
14bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#ifndef LLVM_CLANG_REWRITER_TEST_CONTEXT_H
15bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#define LLVM_CLANG_REWRITER_TEST_CONTEXT_H
16bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
17bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "clang/Basic/Diagnostic.h"
1899eb4a7920667d23a89df8fcc6429d12b36e4d57Douglas Gregor#include "clang/Basic/DiagnosticOptions.h"
19bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "clang/Basic/FileManager.h"
20bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "clang/Basic/LangOptions.h"
21bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "clang/Basic/SourceManager.h"
22bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "clang/Frontend/TextDiagnosticPrinter.h"
23305c613af6cfc40e519c75d9d2c84c6fa9a841c0Ted Kremenek#include "clang/Rewrite/Core/Rewriter.h"
247b699ac3ac8ce48cf9e9387f6b6830f3a8d409d5Manuel Klimek#include "llvm/Support/FileSystem.h"
25bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "llvm/Support/Path.h"
26bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "llvm/Support/raw_ostream.h"
27bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
28bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimeknamespace clang {
29bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
30bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek/// \brief A class that sets up a ready to use Rewriter.
31bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek///
32bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek/// Useful in unit tests that need a Rewriter. Creates all dependencies
33bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek/// of a Rewriter with default values for testing and provides convenience
34bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek/// methods, which help with writing tests that change files.
35bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimekclass RewriterTestContext {
36bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek public:
37bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  RewriterTestContext()
3899eb4a7920667d23a89df8fcc6429d12b36e4d57Douglas Gregor      : DiagOpts(new DiagnosticOptions()),
39cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko        Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
4099eb4a7920667d23a89df8fcc6429d12b36e4d57Douglas Gregor                    &*DiagOpts),
4199eb4a7920667d23a89df8fcc6429d12b36e4d57Douglas Gregor        DiagnosticPrinter(llvm::outs(), &*DiagOpts),
42bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek        Files((FileSystemOptions())),
43bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek        Sources(Diagnostics, Files),
44bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek        Rewrite(Sources, Options) {
45bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    Diagnostics.setClient(&DiagnosticPrinter, false);
46bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
47bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
485bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola  ~RewriterTestContext() {}
49bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
50bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  FileID createInMemoryFile(StringRef Name, StringRef Content) {
51ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    llvm::MemoryBuffer *Source = llvm::MemoryBuffer::getMemBuffer(Content);
52bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    const FileEntry *Entry =
53bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      Files.getVirtualFile(Name, Source->getBufferSize(), 0);
546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    Sources.overrideFileContents(Entry, Source);
55ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    assert(Entry != nullptr);
56bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
57bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
58bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
595bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola  // FIXME: this code is mostly a duplicate of
605bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola  // unittests/Tooling/RefactoringTest.cpp. Figure out a way to share it.
61bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  FileID createOnDiskFile(StringRef Name, StringRef Content) {
625bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    SmallString<1024> Path;
635bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    int FD;
64ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    std::error_code EC = llvm::sys::fs::createTemporaryFile(Name, "", FD, Path);
655bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    assert(!EC);
665bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    (void)EC;
675bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola
685bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    llvm::raw_fd_ostream OutStream(FD, true);
69bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    OutStream << Content;
70bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    OutStream.close();
71bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    const FileEntry *File = Files.getFile(Path);
72ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    assert(File != nullptr);
735bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola
745bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    StringRef Found = TemporaryFiles.GetOrCreateValue(Name, Path.str()).second;
755bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    assert(Found == Path);
765bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    (void)Found;
77bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    return Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
78bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
79bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
80bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  SourceLocation getLocation(FileID ID, unsigned Line, unsigned Column) {
81bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    SourceLocation Result = Sources.translateFileLineCol(
82bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek        Sources.getFileEntryForID(ID), Line, Column);
83bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    assert(Result.isValid());
84bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    return Result;
85bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
86bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
87bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  std::string getRewrittenText(FileID ID) {
88bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    std::string Result;
89bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    llvm::raw_string_ostream OS(Result);
90bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    Rewrite.getEditBuffer(ID).write(OS);
91d6f6569bf693da3f8efd8ce7ae93fbbfccf09753Manuel Klimek    OS.flush();
92bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    return Result;
93bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
94bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
95bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  std::string getFileContentFromDisk(StringRef Name) {
965bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    std::string Path = TemporaryFiles.lookup(Name);
975bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    assert(!Path.empty());
98bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    // We need to read directly from the FileManager without relaying through
99bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    // a FileEntry, as otherwise we'd read through an already opened file
100bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    // descriptor, which might not see the changes made.
101bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    // FIXME: Figure out whether there is a way to get the SourceManger to
102bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    // reopen the file.
1036bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    std::unique_ptr<const llvm::MemoryBuffer> FileBuffer(
104ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        Files.getBufferForFile(Path, nullptr));
1056bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return FileBuffer->getBuffer();
106bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
107bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
108cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
109bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  DiagnosticsEngine Diagnostics;
110bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  TextDiagnosticPrinter DiagnosticPrinter;
111bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  FileManager Files;
112bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  SourceManager Sources;
113bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  LangOptions Options;
114bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  Rewriter Rewrite;
115bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
1167b699ac3ac8ce48cf9e9387f6b6830f3a8d409d5Manuel Klimek  // Will be set once on disk files are generated.
1175bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola  llvm::StringMap<std::string> TemporaryFiles;
118bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek};
119bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
120bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek} // end namespace clang
121bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
122bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#endif
123