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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang/unittests/Tooling/RewriterTestContext.h