1f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek//===- unittest/Tooling/RefactoringTest.cpp - Refactoring unit tests ------===//
2f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek//
3f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek//                     The LLVM Compiler Infrastructure
4f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek//
5f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek// This file is distributed under the University of Illinois Open Source
6f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek// License. See LICENSE.TXT for details.
7f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek//
8f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek//===----------------------------------------------------------------------===//
9f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
10f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "RewriterTestContext.h"
11a13d2bceaea04cb7c16b4cfbeb06f12f8e90c6c9Benjamin Kramer#include "clang/AST/ASTContext.h"
12f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/AST/ASTConsumer.h"
13f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/AST/DeclCXX.h"
14f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/AST/DeclGroup.h"
15f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/AST/RecursiveASTVisitor.h"
16f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Tooling/Refactoring.h"
17f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Basic/Diagnostic.h"
18f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Basic/FileManager.h"
19f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Basic/LangOptions.h"
20f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Basic/SourceManager.h"
21f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Frontend/CompilerInstance.h"
22f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Frontend/DiagnosticOptions.h"
23f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Frontend/FrontendAction.h"
24f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Frontend/TextDiagnosticPrinter.h"
25305c613af6cfc40e519c75d9d2c84c6fa9a841c0Ted Kremenek#include "clang/Rewrite/Core/Rewriter.h"
26f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Tooling/Tooling.h"
27f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "llvm/ADT/SmallString.h"
28f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "llvm/Support/Path.h"
29f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "gtest/gtest.h"
30f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
31f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimeknamespace clang {
32f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimeknamespace tooling {
33f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
34f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekclass ReplacementTest : public ::testing::Test {
35f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek protected:
36f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacement createReplacement(SourceLocation Start, unsigned Length,
37f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                                llvm::StringRef ReplacementText) {
38f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    return Replacement(Context.Sources, Start, Length, ReplacementText);
39f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  }
40f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
41f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  RewriterTestContext Context;
42f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek};
43f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
44f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, CanDeleteAllText) {
45f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  FileID ID = Context.createInMemoryFile("input.cpp", "text");
46f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  SourceLocation Location = Context.getLocation(ID, 1, 1);
47f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacement Replace(createReplacement(Location, 4, ""));
48f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(Replace.apply(Context.Rewrite));
49f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ("", Context.getRewrittenText(ID));
50f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
51f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
52f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, CanDeleteAllTextInTextWithNewlines) {
53f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  FileID ID = Context.createInMemoryFile("input.cpp", "line1\nline2\nline3");
54f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  SourceLocation Location = Context.getLocation(ID, 1, 1);
55f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacement Replace(createReplacement(Location, 17, ""));
56f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(Replace.apply(Context.Rewrite));
57f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ("", Context.getRewrittenText(ID));
58f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
59f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
60f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, CanAddText) {
61f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  FileID ID = Context.createInMemoryFile("input.cpp", "");
62f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  SourceLocation Location = Context.getLocation(ID, 1, 1);
63f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacement Replace(createReplacement(Location, 0, "result"));
64f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(Replace.apply(Context.Rewrite));
65f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ("result", Context.getRewrittenText(ID));
66f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
67f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
68f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, CanReplaceTextAtPosition) {
69f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  FileID ID = Context.createInMemoryFile("input.cpp",
70f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                                         "line1\nline2\nline3\nline4");
71f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  SourceLocation Location = Context.getLocation(ID, 2, 3);
72f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacement Replace(createReplacement(Location, 12, "x"));
73f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(Replace.apply(Context.Rewrite));
74f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ("line1\nlixne4", Context.getRewrittenText(ID));
75f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
76f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
77f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, CanReplaceTextAtPositionMultipleTimes) {
78f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  FileID ID = Context.createInMemoryFile("input.cpp",
79f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                                         "line1\nline2\nline3\nline4");
80f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  SourceLocation Location1 = Context.getLocation(ID, 2, 3);
81f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacement Replace1(createReplacement(Location1, 12, "x\ny\n"));
82f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(Replace1.apply(Context.Rewrite));
83f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ("line1\nlix\ny\nne4", Context.getRewrittenText(ID));
84f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
85f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  // Since the original source has not been modified, the (4, 4) points to the
86f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  // 'e' in the original content.
87f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  SourceLocation Location2 = Context.getLocation(ID, 4, 4);
88f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacement Replace2(createReplacement(Location2, 1, "f"));
89f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(Replace2.apply(Context.Rewrite));
90f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ("line1\nlix\ny\nnf4", Context.getRewrittenText(ID));
91f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
92f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
93f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, ApplyFailsForNonExistentLocation) {
94f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacement Replace("nonexistent-file.cpp", 0, 1, "");
95f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_FALSE(Replace.apply(Context.Rewrite));
96f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
97f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
98f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, CanRetrivePath) {
99f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacement Replace("/path/to/file.cpp", 0, 1, "");
100f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ("/path/to/file.cpp", Replace.getFilePath());
101f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
102f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
103f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, ReturnsInvalidPath) {
104f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacement Replace1(Context.Sources, SourceLocation(), 0, "");
105f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(Replace1.getFilePath().empty());
106f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
107f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacement Replace2;
108f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(Replace2.getFilePath().empty());
109f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
110f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
111f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, CanApplyReplacements) {
112f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  FileID ID = Context.createInMemoryFile("input.cpp",
113f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                                         "line1\nline2\nline3\nline4");
114f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacements Replaces;
115f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
116f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                              5, "replaced"));
117f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 3, 1),
118f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                              5, "other"));
119f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
120f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));
121f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
122f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
123f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, SkipsDuplicateReplacements) {
124f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  FileID ID = Context.createInMemoryFile("input.cpp",
125f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                                         "line1\nline2\nline3\nline4");
126f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacements Replaces;
127f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
128f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                              5, "replaced"));
129f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
130f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                              5, "replaced"));
131f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
132f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                              5, "replaced"));
133f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
134f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ("line1\nreplaced\nline3\nline4", Context.getRewrittenText(ID));
135f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
136f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
137f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, ApplyAllFailsIfOneApplyFails) {
138f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  // This test depends on the value of the file name of an invalid source
139f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  // location being in the range ]a, z[.
140f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  FileID IDa = Context.createInMemoryFile("a.cpp", "text");
141f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  FileID IDz = Context.createInMemoryFile("z.cpp", "text");
142f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacements Replaces;
143f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replaces.insert(Replacement(Context.Sources, Context.getLocation(IDa, 1, 1),
144f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                              4, "a"));
145f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replaces.insert(Replacement(Context.Sources, SourceLocation(),
146f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                              5, "2"));
147f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replaces.insert(Replacement(Context.Sources, Context.getLocation(IDz, 1, 1),
148f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                              4, "z"));
149f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_FALSE(applyAllReplacements(Replaces, Context.Rewrite));
150f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ("a", Context.getRewrittenText(IDa));
151f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ("z", Context.getRewrittenText(IDz));
152f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
153f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
154f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekclass FlushRewrittenFilesTest : public ::testing::Test {
155f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek public:
156f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  FlushRewrittenFilesTest() {
157f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    std::string ErrorInfo;
158f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    TemporaryDirectory = llvm::sys::Path::GetTemporaryDirectory(&ErrorInfo);
159f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    assert(ErrorInfo.empty());
160f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  }
161f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
162f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  ~FlushRewrittenFilesTest() {
163f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    std::string ErrorInfo;
164f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    TemporaryDirectory.eraseFromDisk(true, &ErrorInfo);
165f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    assert(ErrorInfo.empty());
166f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  }
167f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
168f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  FileID createFile(llvm::StringRef Name, llvm::StringRef Content) {
169f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    llvm::SmallString<1024> Path(TemporaryDirectory.str());
170f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    llvm::sys::path::append(Path, Name);
171f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    std::string ErrorInfo;
172f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    llvm::raw_fd_ostream OutStream(Path.c_str(),
173f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                                   ErrorInfo, llvm::raw_fd_ostream::F_Binary);
174f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    assert(ErrorInfo.empty());
175f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    OutStream << Content;
176f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    OutStream.close();
177f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    const FileEntry *File = Context.Files.getFile(Path);
178f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    assert(File != NULL);
179f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    return Context.Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
180f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  }
181f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
182f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  std::string getFileContentFromDisk(llvm::StringRef Name) {
183f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    llvm::SmallString<1024> Path(TemporaryDirectory.str());
184f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    llvm::sys::path::append(Path, Name);
185f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    // We need to read directly from the FileManager without relaying through
186f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    // a FileEntry, as otherwise we'd read through an already opened file
187f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    // descriptor, which might not see the changes made.
188f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    // FIXME: Figure out whether there is a way to get the SourceManger to
189f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    // reopen the file.
190f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    return Context.Files.getBufferForFile(Path, NULL)->getBuffer();
191f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  }
192f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
193f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  llvm::sys::Path TemporaryDirectory;
194f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  RewriterTestContext Context;
195f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek};
196f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
197f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(FlushRewrittenFilesTest, StoresChangesOnDisk) {
198f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  FileID ID = createFile("input.cpp", "line1\nline2\nline3\nline4");
199f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacements Replaces;
200f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
201f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                              5, "replaced"));
202f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
203f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_FALSE(Context.Rewrite.overwriteChangedFiles());
204f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ("line1\nreplaced\nline3\nline4",
205f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek            getFileContentFromDisk("input.cpp"));
206f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
207f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
208f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimeknamespace {
209f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimektemplate <typename T>
210f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekclass TestVisitor : public clang::RecursiveASTVisitor<T> {
211f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekpublic:
212f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  bool runOver(StringRef Code) {
213f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    return runToolOnCode(new TestAction(this), Code);
214f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  }
215f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
216f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekprotected:
217f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  clang::SourceManager *SM;
218f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
219f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekprivate:
220f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  class FindConsumer : public clang::ASTConsumer {
221f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  public:
222f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {}
223f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
224f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    virtual void HandleTranslationUnit(clang::ASTContext &Context) {
225f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek      Visitor->TraverseDecl(Context.getTranslationUnitDecl());
226f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    }
227f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
228f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  private:
229f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    TestVisitor *Visitor;
230f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  };
231f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
232f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  class TestAction : public clang::ASTFrontendAction {
233f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  public:
234f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
235f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
236f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    virtual clang::ASTConsumer* CreateASTConsumer(
237f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek        clang::CompilerInstance& compiler, llvm::StringRef dummy) {
238f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek      Visitor->SM = &compiler.getSourceManager();
239f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek      /// TestConsumer will be deleted by the framework calling us.
240f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek      return new FindConsumer(Visitor);
241f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    }
242f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
243f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  private:
244f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    TestVisitor *Visitor;
245f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  };
246f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek};
247f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} // end namespace
248f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
249f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekvoid expectReplacementAt(const Replacement &Replace,
250f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek                         StringRef File, unsigned Offset, unsigned Length) {
251f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  ASSERT_TRUE(Replace.isApplicable());
252f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ(File, Replace.getFilePath());
253f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ(Offset, Replace.getOffset());
254f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_EQ(Length, Replace.getLength());
255f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
256f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
257f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekclass ClassDeclXVisitor : public TestVisitor<ClassDeclXVisitor> {
258f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekpublic:
259f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  bool VisitCXXRecordDecl(CXXRecordDecl *Record) {
260f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    if (Record->getName() == "X") {
261f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek      Replace = Replacement(*SM, Record, "");
262f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    }
263f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    return true;
264f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  }
265f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacement Replace;
266f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek};
267f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
268f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST(Replacement, CanBeConstructedFromNode) {
269f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  ClassDeclXVisitor ClassDeclX;
270f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(ClassDeclX.runOver("     class X;"));
271f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  expectReplacementAt(ClassDeclX.Replace, "input.cc", 5, 7);
272f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
273f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
274f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST(Replacement, ReplacesAtSpellingLocation) {
275f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  ClassDeclXVisitor ClassDeclX;
276f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(ClassDeclX.runOver("#define A(Y) Y\nA(class X);"));
277f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  expectReplacementAt(ClassDeclX.Replace, "input.cc", 17, 7);
278f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
279f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
280f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekclass CallToFVisitor : public TestVisitor<CallToFVisitor> {
281f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekpublic:
282f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  bool VisitCallExpr(CallExpr *Call) {
283f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    if (Call->getDirectCallee()->getName() == "F") {
284f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek      Replace = Replacement(*SM, Call, "");
285f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    }
286f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek    return true;
287f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  }
288f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  Replacement Replace;
289f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek};
290f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
291f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST(Replacement, FunctionCall) {
292f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  CallToFVisitor CallToF;
293f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(CallToF.runOver("void F(); void G() { F(); }"));
294f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  expectReplacementAt(CallToF.Replace, "input.cc", 21, 3);
295f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
296f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
297f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST(Replacement, TemplatedFunctionCall) {
298f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  CallToFVisitor CallToF;
299f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  EXPECT_TRUE(CallToF.runOver(
300f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek        "template <typename T> void F(); void G() { F<int>(); }"));
301f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek  expectReplacementAt(CallToF.Replace, "input.cc", 43, 8);
302f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}
303f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek
304f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} // end namespace tooling
305f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} // end namespace clang
306