1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
//===--- RewriterTestContext.h ----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines a utility class for Rewriter related tests.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_UNITTESTS_TOOLING_REWRITERTESTCONTEXT_H
#define LLVM_CLANG_UNITTESTS_TOOLING_REWRITERTESTCONTEXT_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
namespace clang {
/// \brief A very simple diagnostic consumer that prints to stderr and keeps
/// track of the number of diagnostics.
///
/// This avoids a dependency on clangFrontend for FormatTests.
struct RewriterDiagnosticConsumer : public DiagnosticConsumer {
RewriterDiagnosticConsumer() : NumDiagnosticsSeen(0) {}
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) override {
++NumDiagnosticsSeen;
SmallString<100> OutStr;
Info.FormatDiagnostic(OutStr);
llvm::errs() << OutStr;
}
unsigned NumDiagnosticsSeen;
};
/// \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()
: DiagOpts(new DiagnosticOptions()),
Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
&*DiagOpts),
InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
OverlayFileSystem(
new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())),
Files(FileSystemOptions(), OverlayFileSystem),
Sources(Diagnostics, Files), Rewrite(Sources, Options) {
Diagnostics.setClient(&DiagnosticPrinter, false);
// FIXME: To make these tests truly in-memory, we need to overlay the
// builtin headers.
OverlayFileSystem->pushOverlay(InMemoryFileSystem);
}
~RewriterTestContext() {}
FileID createInMemoryFile(StringRef Name, StringRef Content) {
std::unique_ptr<llvm::MemoryBuffer> Source =
llvm::MemoryBuffer::getMemBuffer(Content);
InMemoryFileSystem->addFile(Name, 0, std::move(Source));
auto Entry = Files.getOptionalFileRef(Name);
assert(Entry);
return Sources.createFileID(*Entry, SourceLocation(), SrcMgr::C_User);
}
// FIXME: this code is mostly a duplicate of
// unittests/Tooling/RefactoringTest.cpp. Figure out a way to share it.
FileID createOnDiskFile(StringRef Name, StringRef Content) {
SmallString<1024> Path;
int FD;
std::error_code EC = llvm::sys::fs::createTemporaryFile(Name, "", FD, Path);
assert(!EC);
(void)EC;
llvm::raw_fd_ostream OutStream(FD, true);
OutStream << Content;
OutStream.close();
auto File = Files.getOptionalFileRef(Path);
assert(File);
StringRef Found =
TemporaryFiles.insert(std::make_pair(Name, std::string(Path.str())))
.first->second;
assert(Found == Path);
(void)Found;
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);
OS.flush();
return Result;
}
std::string getFileContentFromDisk(StringRef Name) {
std::string Path = TemporaryFiles.lookup(Name);
assert(!Path.empty());
// 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.
auto FileBuffer = Files.getBufferForFile(Path);
return std::string((*FileBuffer)->getBuffer());
}
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
DiagnosticsEngine Diagnostics;
RewriterDiagnosticConsumer DiagnosticPrinter;
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem;
FileManager Files;
SourceManager Sources;
LangOptions Options;
Rewriter Rewrite;
// Will be set once on disk files are generated.
llvm::StringMap<std::string> TemporaryFiles;
};
} // end namespace clang
#endif
|