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
14176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines#ifndef LLVM_CLANG_UNITTESTS_TOOLING_REWRITERTESTCONTEXT_H
15176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines#define LLVM_CLANG_UNITTESTS_TOOLING_REWRITERTESTCONTEXT_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:
3787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar   RewriterTestContext()
3887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar       : DiagOpts(new DiagnosticOptions()),
3987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar         Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
4087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                     &*DiagOpts),
4187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar         DiagnosticPrinter(llvm::outs(), &*DiagOpts),
4287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar         InMemoryFileSystem(new vfs::InMemoryFileSystem),
4387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar         OverlayFileSystem(
4487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar             new vfs::OverlayFileSystem(vfs::getRealFileSystem())),
4587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar         Files(FileSystemOptions(), OverlayFileSystem),
4687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar         Sources(Diagnostics, Files), Rewrite(Sources, Options) {
47bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    Diagnostics.setClient(&DiagnosticPrinter, false);
4887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    // FIXME: To make these tests truly in-memory, we need to overlay the
4987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    // builtin headers.
5087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    OverlayFileSystem->pushOverlay(InMemoryFileSystem);
51bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
52bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
535bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola  ~RewriterTestContext() {}
54bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
55bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  FileID createInMemoryFile(StringRef Name, StringRef Content) {
56176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    std::unique_ptr<llvm::MemoryBuffer> Source =
57176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        llvm::MemoryBuffer::getMemBuffer(Content);
5887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    InMemoryFileSystem->addFile(Name, 0, std::move(Source));
5987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
6087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    const FileEntry *Entry = Files.getFile(Name);
61c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    assert(Entry != nullptr);
62bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
63bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
64bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
655bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola  // FIXME: this code is mostly a duplicate of
665bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola  // unittests/Tooling/RefactoringTest.cpp. Figure out a way to share it.
67bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  FileID createOnDiskFile(StringRef Name, StringRef Content) {
685bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    SmallString<1024> Path;
695bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    int FD;
70c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    std::error_code EC = llvm::sys::fs::createTemporaryFile(Name, "", FD, Path);
715bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    assert(!EC);
725bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    (void)EC;
735bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola
745bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    llvm::raw_fd_ostream OutStream(FD, true);
75bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    OutStream << Content;
76bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    OutStream.close();
77bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    const FileEntry *File = Files.getFile(Path);
78c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    assert(File != nullptr);
795bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola
80176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    StringRef Found =
81176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        TemporaryFiles.insert(std::make_pair(Name, Path.str())).first->second;
825bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    assert(Found == Path);
835bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    (void)Found;
84bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    return Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
85bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
86bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
87bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  SourceLocation getLocation(FileID ID, unsigned Line, unsigned Column) {
88bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    SourceLocation Result = Sources.translateFileLineCol(
89bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek        Sources.getFileEntryForID(ID), Line, Column);
90bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    assert(Result.isValid());
91bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    return Result;
92bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
93bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
94bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  std::string getRewrittenText(FileID ID) {
95bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    std::string Result;
96bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    llvm::raw_string_ostream OS(Result);
97bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    Rewrite.getEditBuffer(ID).write(OS);
98d6f6569bf693da3f8efd8ce7ae93fbbfccf09753Manuel Klimek    OS.flush();
99bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    return Result;
100bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
101bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
102bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  std::string getFileContentFromDisk(StringRef Name) {
1035bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    std::string Path = TemporaryFiles.lookup(Name);
1045bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola    assert(!Path.empty());
105bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    // We need to read directly from the FileManager without relaying through
106bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    // a FileEntry, as otherwise we'd read through an already opened file
107bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    // descriptor, which might not see the changes made.
108bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    // FIXME: Figure out whether there is a way to get the SourceManger to
109bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    // reopen the file.
110176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    auto FileBuffer = Files.getBufferForFile(Path);
111176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    return (*FileBuffer)->getBuffer();
112bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
113bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
114cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
115bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  DiagnosticsEngine Diagnostics;
116bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  TextDiagnosticPrinter DiagnosticPrinter;
11787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem;
11887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFileSystem;
119bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  FileManager Files;
120bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  SourceManager Sources;
121bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  LangOptions Options;
122bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  Rewriter Rewrite;
123bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
1247b699ac3ac8ce48cf9e9387f6b6830f3a8d409d5Manuel Klimek  // Will be set once on disk files are generated.
1255bb5f6a84ef98e410fdc89d82f4b7565fb5616e5Rafael Espindola  llvm::StringMap<std::string> TemporaryFiles;
126bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek};
127bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
128bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek} // end namespace clang
129bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
130bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#endif
131