blob: c29f8d7d71230ddb974ed21b99517c3d5e75c14a [file] [log] [blame]
Manuel Klimek3f001342012-05-23 16:29:20 +00001//===- unittest/Tooling/RefactoringTest.cpp - Refactoring unit tests ------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Eric Liu40ef2fb2016-08-01 10:16:37 +000010#include "ReplacementTest.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000011#include "RewriterTestContext.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000012#include "clang/AST/ASTConsumer.h"
Chandler Carruth320d9662012-12-04 09:45:34 +000013#include "clang/AST/ASTContext.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000014#include "clang/AST/DeclCXX.h"
15#include "clang/AST/DeclGroup.h"
16#include "clang/AST/RecursiveASTVisitor.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000017#include "clang/Basic/Diagnostic.h"
Douglas Gregor275e8832012-10-23 22:55:10 +000018#include "clang/Basic/DiagnosticOptions.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000019#include "clang/Basic/FileManager.h"
20#include "clang/Basic/LangOptions.h"
21#include "clang/Basic/SourceManager.h"
Eric Liucf2913c2016-11-07 06:08:23 +000022#include "clang/Basic/VirtualFileSystem.h"
Eric Liu4c1ef97a2016-03-29 16:31:53 +000023#include "clang/Format/Format.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000024#include "clang/Frontend/CompilerInstance.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000025#include "clang/Frontend/FrontendAction.h"
26#include "clang/Frontend/TextDiagnosticPrinter.h"
Ted Kremenekcdf81492012-09-01 05:09:24 +000027#include "clang/Rewrite/Core/Rewriter.h"
Chandler Carruth320d9662012-12-04 09:45:34 +000028#include "clang/Tooling/Refactoring.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000029#include "clang/Tooling/Tooling.h"
30#include "llvm/ADT/SmallString.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000031#include "gtest/gtest.h"
32
33namespace clang {
34namespace tooling {
35
Manuel Klimek3f001342012-05-23 16:29:20 +000036TEST_F(ReplacementTest, CanDeleteAllText) {
37 FileID ID = Context.createInMemoryFile("input.cpp", "text");
38 SourceLocation Location = Context.getLocation(ID, 1, 1);
39 Replacement Replace(createReplacement(Location, 4, ""));
40 EXPECT_TRUE(Replace.apply(Context.Rewrite));
41 EXPECT_EQ("", Context.getRewrittenText(ID));
42}
43
44TEST_F(ReplacementTest, CanDeleteAllTextInTextWithNewlines) {
45 FileID ID = Context.createInMemoryFile("input.cpp", "line1\nline2\nline3");
46 SourceLocation Location = Context.getLocation(ID, 1, 1);
47 Replacement Replace(createReplacement(Location, 17, ""));
48 EXPECT_TRUE(Replace.apply(Context.Rewrite));
49 EXPECT_EQ("", Context.getRewrittenText(ID));
50}
51
52TEST_F(ReplacementTest, CanAddText) {
53 FileID ID = Context.createInMemoryFile("input.cpp", "");
54 SourceLocation Location = Context.getLocation(ID, 1, 1);
55 Replacement Replace(createReplacement(Location, 0, "result"));
56 EXPECT_TRUE(Replace.apply(Context.Rewrite));
57 EXPECT_EQ("result", Context.getRewrittenText(ID));
58}
59
60TEST_F(ReplacementTest, CanReplaceTextAtPosition) {
61 FileID ID = Context.createInMemoryFile("input.cpp",
62 "line1\nline2\nline3\nline4");
63 SourceLocation Location = Context.getLocation(ID, 2, 3);
64 Replacement Replace(createReplacement(Location, 12, "x"));
65 EXPECT_TRUE(Replace.apply(Context.Rewrite));
66 EXPECT_EQ("line1\nlixne4", Context.getRewrittenText(ID));
67}
68
69TEST_F(ReplacementTest, CanReplaceTextAtPositionMultipleTimes) {
70 FileID ID = Context.createInMemoryFile("input.cpp",
71 "line1\nline2\nline3\nline4");
72 SourceLocation Location1 = Context.getLocation(ID, 2, 3);
73 Replacement Replace1(createReplacement(Location1, 12, "x\ny\n"));
74 EXPECT_TRUE(Replace1.apply(Context.Rewrite));
75 EXPECT_EQ("line1\nlix\ny\nne4", Context.getRewrittenText(ID));
76
77 // Since the original source has not been modified, the (4, 4) points to the
78 // 'e' in the original content.
79 SourceLocation Location2 = Context.getLocation(ID, 4, 4);
80 Replacement Replace2(createReplacement(Location2, 1, "f"));
81 EXPECT_TRUE(Replace2.apply(Context.Rewrite));
82 EXPECT_EQ("line1\nlix\ny\nnf4", Context.getRewrittenText(ID));
83}
84
85TEST_F(ReplacementTest, ApplyFailsForNonExistentLocation) {
86 Replacement Replace("nonexistent-file.cpp", 0, 1, "");
87 EXPECT_FALSE(Replace.apply(Context.Rewrite));
88}
89
90TEST_F(ReplacementTest, CanRetrivePath) {
91 Replacement Replace("/path/to/file.cpp", 0, 1, "");
92 EXPECT_EQ("/path/to/file.cpp", Replace.getFilePath());
93}
94
95TEST_F(ReplacementTest, ReturnsInvalidPath) {
96 Replacement Replace1(Context.Sources, SourceLocation(), 0, "");
97 EXPECT_TRUE(Replace1.getFilePath().empty());
98
99 Replacement Replace2;
100 EXPECT_TRUE(Replace2.getFilePath().empty());
101}
102
Eric Liue86a5f42016-11-22 13:46:42 +0000103// Checks that an llvm::Error instance contains a ReplacementError with expected
104// error code, expected new replacement, and expected existing replacement.
105static bool checkReplacementError(
106 llvm::Error&& Error, replacement_error ExpectedErr,
107 llvm::Optional<Replacement> ExpectedExisting,
108 llvm::Optional<Replacement> ExpectedNew) {
109 if (!Error) {
110 llvm::errs() << "Error is a success.";
111 return false;
112 }
113 std::string ErrorMessage;
114 llvm::raw_string_ostream OS(ErrorMessage);
115 llvm::handleAllErrors(std::move(Error), [&](const ReplacementError &RE) {
116 llvm::errs() << "Handling error...\n";
117 if (ExpectedErr != RE.get())
118 OS << "Unexpected error code: " << int(RE.get()) << "\n";
119 if (ExpectedExisting != RE.getExistingReplacement()) {
120 OS << "Expected Existing != Actual Existing.\n";
121 if (ExpectedExisting.hasValue())
122 OS << "Expected existing replacement: " << ExpectedExisting->toString()
123 << "\n";
124 if (RE.getExistingReplacement().hasValue())
125 OS << "Actual existing replacement: "
126 << RE.getExistingReplacement()->toString() << "\n";
127 }
128 if (ExpectedNew != RE.getNewReplacement()) {
129 OS << "Expected New != Actual New.\n";
130 if (ExpectedNew.hasValue())
131 OS << "Expected new replacement: " << ExpectedNew->toString() << "\n";
132 if (RE.getNewReplacement().hasValue())
133 OS << "Actual new replacement: " << RE.getNewReplacement()->toString()
134 << "\n";
135 }
136 });
137 OS.flush();
138 if (ErrorMessage.empty()) return true;
139 llvm::errs() << ErrorMessage;
140 return false;
141}
142
Eric Liu40ef2fb2016-08-01 10:16:37 +0000143TEST_F(ReplacementTest, FailAddReplacements) {
144 Replacements Replaces;
Eric Liu6ef82b62016-09-28 11:02:16 +0000145 Replacement Deletion("x.cc", 0, 10, "3");
146 auto Err = Replaces.add(Deletion);
Eric Liu40ef2fb2016-08-01 10:16:37 +0000147 EXPECT_TRUE(!Err);
148 llvm::consumeError(std::move(Err));
Eric Liue86a5f42016-11-22 13:46:42 +0000149
150 Replacement OverlappingReplacement("x.cc", 0, 2, "a");
151 Err = Replaces.add(OverlappingReplacement);
152 EXPECT_TRUE(checkReplacementError(std::move(Err),
153 replacement_error::overlap_conflict,
154 Deletion, OverlappingReplacement));
155
156 Replacement ContainedReplacement("x.cc", 2, 2, "a");
157 Err = Replaces.add(Replacement(ContainedReplacement));
158 EXPECT_TRUE(checkReplacementError(std::move(Err),
159 replacement_error::overlap_conflict,
160 Deletion, ContainedReplacement));
161
162 Replacement WrongPathReplacement("y.cc", 20, 2, "");
163 Err = Replaces.add(WrongPathReplacement);
164 EXPECT_TRUE(checkReplacementError(std::move(Err),
165 replacement_error::wrong_file_path,
166 Deletion, WrongPathReplacement));
167
Eric Liu6ef82b62016-09-28 11:02:16 +0000168 EXPECT_EQ(1u, Replaces.size());
169 EXPECT_EQ(Deletion, *Replaces.begin());
170}
171
172TEST_F(ReplacementTest, DeletionInReplacements) {
173 Replacements Replaces;
174 Replacement R("x.cc", 0, 10, "3");
175 auto Err = Replaces.add(R);
176 EXPECT_TRUE(!Err);
177 llvm::consumeError(std::move(Err));
178 Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
179 EXPECT_TRUE(!Err);
180 llvm::consumeError(std::move(Err));
181 Err = Replaces.add(Replacement("x.cc", 2, 2, ""));
182 EXPECT_TRUE(!Err);
183 llvm::consumeError(std::move(Err));
184 EXPECT_EQ(1u, Replaces.size());
185 EXPECT_EQ(R, *Replaces.begin());
186}
187
188TEST_F(ReplacementTest, OverlappingReplacements) {
189 Replacements Replaces;
190 auto Err = Replaces.add(Replacement("x.cc", 0, 3, "345"));
191 EXPECT_TRUE(!Err);
192 llvm::consumeError(std::move(Err));
193 Err = Replaces.add(Replacement("x.cc", 2, 3, "543"));
194 EXPECT_TRUE(!Err);
195 llvm::consumeError(std::move(Err));
196
197 EXPECT_EQ(1u, Replaces.size());
198 EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin());
199
200 Err = Replaces.add(Replacement("x.cc", 2, 1, "5"));
201 EXPECT_TRUE(!Err);
202 llvm::consumeError(std::move(Err));
203 EXPECT_EQ(1u, Replaces.size());
204 EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin());
Eric Liu40ef2fb2016-08-01 10:16:37 +0000205}
206
Eric Liu9df9b6f2016-09-19 08:40:42 +0000207TEST_F(ReplacementTest, AddAdjacentInsertionAndReplacement) {
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000208 Replacements Replaces;
209 // Test adding an insertion at the offset of an existing replacement.
210 auto Err = Replaces.add(Replacement("x.cc", 10, 3, "replace"));
211 EXPECT_TRUE(!Err);
212 llvm::consumeError(std::move(Err));
213 Err = Replaces.add(Replacement("x.cc", 10, 0, "insert"));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000214 EXPECT_TRUE(!Err);
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000215 llvm::consumeError(std::move(Err));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000216 EXPECT_EQ(Replaces.size(), 2u);
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000217
218 Replaces.clear();
219 // Test overlap with an existing insertion.
220 Err = Replaces.add(Replacement("x.cc", 10, 0, "insert"));
221 EXPECT_TRUE(!Err);
222 llvm::consumeError(std::move(Err));
223 Err = Replaces.add(Replacement("x.cc", 10, 3, "replace"));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000224 EXPECT_TRUE(!Err);
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000225 llvm::consumeError(std::move(Err));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000226 EXPECT_EQ(Replaces.size(), 2u);
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000227}
228
Eric Liu6ef82b62016-09-28 11:02:16 +0000229TEST_F(ReplacementTest, MergeNewDeletions) {
230 Replacements Replaces;
231 Replacement ContainingReplacement("x.cc", 0, 10, "");
232 auto Err = Replaces.add(ContainingReplacement);
233 EXPECT_TRUE(!Err);
234 llvm::consumeError(std::move(Err));
235
236 Err = Replaces.add(Replacement("x.cc", 5, 3, ""));
237 EXPECT_TRUE(!Err);
238 llvm::consumeError(std::move(Err));
239
240 Err = Replaces.add(Replacement("x.cc", 0, 10, ""));
241 EXPECT_TRUE(!Err);
242 llvm::consumeError(std::move(Err));
243
244 Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
245 EXPECT_TRUE(!Err);
246 llvm::consumeError(std::move(Err));
247
248 EXPECT_EQ(1u, Replaces.size());
249 EXPECT_EQ(*Replaces.begin(), ContainingReplacement);
250}
251
252TEST_F(ReplacementTest, MergeOverlappingButNotAdjacentReplacement) {
253 Replacements Replaces;
254 auto Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
255 EXPECT_TRUE(!Err);
256 llvm::consumeError(std::move(Err));
257
258 Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
259 EXPECT_TRUE(!Err);
260 llvm::consumeError(std::move(Err));
261
262 Replacement After = Replacement("x.cc", 10, 5, "");
263 Err = Replaces.add(After);
264 EXPECT_TRUE(!Err);
265 llvm::consumeError(std::move(Err));
266
267 Replacement ContainingReplacement("x.cc", 0, 10, "");
268 Err = Replaces.add(ContainingReplacement);
269 EXPECT_TRUE(!Err);
270 llvm::consumeError(std::move(Err));
271
272 EXPECT_EQ(2u, Replaces.size());
273 EXPECT_EQ(*Replaces.begin(), ContainingReplacement);
274 EXPECT_EQ(*(++Replaces.begin()), After);
275}
276
277TEST_F(ReplacementTest, InsertionBeforeMergedDeletions) {
278 Replacements Replaces;
279
280 Replacement Insertion("x.cc", 0, 0, "123");
281 auto Err = Replaces.add(Insertion);
282 EXPECT_TRUE(!Err);
283 llvm::consumeError(std::move(Err));
284
285 Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
286 EXPECT_TRUE(!Err);
287 llvm::consumeError(std::move(Err));
288
289 Replacement Deletion("x.cc", 0, 10, "");
290 Err = Replaces.add(Deletion);
291 EXPECT_TRUE(!Err);
292 llvm::consumeError(std::move(Err));
293
294 EXPECT_EQ(2u, Replaces.size());
295 EXPECT_EQ(*Replaces.begin(), Insertion);
296 EXPECT_EQ(*(++Replaces.begin()), Deletion);
297}
298
299TEST_F(ReplacementTest, MergeOverlappingDeletions) {
300 Replacements Replaces;
301 auto Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
302 EXPECT_TRUE(!Err);
303 llvm::consumeError(std::move(Err));
304
305 Err = Replaces.add(Replacement("x.cc", 0, 5, ""));
306 EXPECT_TRUE(!Err);
307 llvm::consumeError(std::move(Err));
308
309 EXPECT_EQ(1u, Replaces.size());
310 EXPECT_EQ(Replacement("x.cc", 0, 5, ""), *Replaces.begin());
311
312 Err = Replaces.add(Replacement("x.cc", 1, 5, ""));
313 EXPECT_TRUE(!Err);
314 llvm::consumeError(std::move(Err));
315 EXPECT_EQ(1u, Replaces.size());
316 EXPECT_EQ(Replacement("x.cc", 0, 6, ""), *Replaces.begin());
317}
318
319TEST_F(ReplacementTest, FailedMergeExistingDeletions) {
320 Replacements Replaces;
321 Replacement First("x.cc", 0, 2, "");
322 auto Err = Replaces.add(First);
323 EXPECT_TRUE(!Err);
324 llvm::consumeError(std::move(Err));
325
326 Replacement Second("x.cc", 5, 5, "");
327 Err = Replaces.add(Second);
328 EXPECT_TRUE(!Err);
329 llvm::consumeError(std::move(Err));
330
331 Err = Replaces.add(Replacement("x.cc", 1, 10, ""));
332 EXPECT_TRUE(!Err);
333 llvm::consumeError(std::move(Err));
334
335 EXPECT_EQ(1u, Replaces.size());
336 EXPECT_EQ(Replacement("x.cc", 0, 11, ""), *Replaces.begin());
337}
338
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000339TEST_F(ReplacementTest, FailAddRegression) {
340 Replacements Replaces;
341 // Create two replacements, where the second one is an insertion of the empty
342 // string exactly at the end of the first one.
343 auto Err = Replaces.add(Replacement("x.cc", 0, 10, "1"));
344 EXPECT_TRUE(!Err);
345 llvm::consumeError(std::move(Err));
346 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
347 EXPECT_TRUE(!Err);
348 llvm::consumeError(std::move(Err));
349
350 // Make sure we find the overlap with the first entry when inserting a
351 // replacement that ends exactly at the seam of the existing replacements.
Eric Liue86a5f42016-11-22 13:46:42 +0000352 Replacement OverlappingReplacement("x.cc", 5, 5, "fail");
353 Err = Replaces.add(OverlappingReplacement);
354 EXPECT_TRUE(checkReplacementError(std::move(Err),
355 replacement_error::overlap_conflict,
356 *Replaces.begin(), OverlappingReplacement));
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000357
358 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
Eric Liu6ef82b62016-09-28 11:02:16 +0000359 EXPECT_TRUE(!Err);
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000360 llvm::consumeError(std::move(Err));
361}
362
Eric Liu9df9b6f2016-09-19 08:40:42 +0000363TEST_F(ReplacementTest, InsertAtOffsetOfReplacement) {
Manuel Klimek16c6d0a2016-08-03 15:12:00 +0000364 Replacements Replaces;
365 auto Err = Replaces.add(Replacement("x.cc", 10, 2, ""));
366 EXPECT_TRUE(!Err);
367 llvm::consumeError(std::move(Err));
368 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000369 EXPECT_TRUE(!Err);
Manuel Klimek16c6d0a2016-08-03 15:12:00 +0000370 llvm::consumeError(std::move(Err));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000371 EXPECT_EQ(Replaces.size(), 2u);
372
373 Replaces.clear();
374 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
375 EXPECT_TRUE(!Err);
376 llvm::consumeError(std::move(Err));
377 Err = Replaces.add(Replacement("x.cc", 10, 2, ""));
378 EXPECT_TRUE(!Err);
379 llvm::consumeError(std::move(Err));
380 EXPECT_EQ(Replaces.size(), 2u);
Manuel Klimek16c6d0a2016-08-03 15:12:00 +0000381}
382
Eric Liu6ef82b62016-09-28 11:02:16 +0000383TEST_F(ReplacementTest, AddInsertAtOtherInsertWhenOderIndependent) {
Manuel Klimek16c6d0a2016-08-03 15:12:00 +0000384 Replacements Replaces;
385 auto Err = Replaces.add(Replacement("x.cc", 10, 0, "a"));
386 EXPECT_TRUE(!Err);
387 llvm::consumeError(std::move(Err));
Eric Liue86a5f42016-11-22 13:46:42 +0000388 Replacement ConflictInsertion("x.cc", 10, 0, "b");
389 Err = Replaces.add(ConflictInsertion);
390 EXPECT_TRUE(checkReplacementError(std::move(Err),
391 replacement_error::insert_conflict,
392 *Replaces.begin(), ConflictInsertion));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000393
394 Replaces.clear();
Eric Liu6ef82b62016-09-28 11:02:16 +0000395 Err = Replaces.add(Replacement("x.cc", 10, 0, "a"));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000396 EXPECT_TRUE(!Err);
397 llvm::consumeError(std::move(Err));
Eric Liu6ef82b62016-09-28 11:02:16 +0000398 Err = Replaces.add(Replacement("x.cc", 10, 0, "aa"));
399 EXPECT_TRUE(!Err);
Eric Liu9df9b6f2016-09-19 08:40:42 +0000400 llvm::consumeError(std::move(Err));
Eric Liu6ef82b62016-09-28 11:02:16 +0000401 EXPECT_EQ(1u, Replaces.size());
402 EXPECT_EQ(Replacement("x.cc", 10, 0, "aaa"), *Replaces.begin());
Eric Liu9df9b6f2016-09-19 08:40:42 +0000403
404 Replaces.clear();
405 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
406 EXPECT_TRUE(!Err);
407 llvm::consumeError(std::move(Err));
408 Err = Replaces.add(Replacement("x.cc", 10, 3, ""));
409 EXPECT_TRUE(!Err);
410 llvm::consumeError(std::move(Err));
411 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
Eric Liu6ef82b62016-09-28 11:02:16 +0000412 EXPECT_TRUE(!Err);
Eric Liu9df9b6f2016-09-19 08:40:42 +0000413 llvm::consumeError(std::move(Err));
Eric Liu6ef82b62016-09-28 11:02:16 +0000414 EXPECT_EQ(2u, Replaces.size());
415 EXPECT_EQ(Replacement("x.cc", 10, 0, ""), *Replaces.begin());
416 EXPECT_EQ(Replacement("x.cc", 10, 3, ""), *std::next(Replaces.begin()));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000417}
418
419TEST_F(ReplacementTest, InsertBetweenAdjacentReplacements) {
420 Replacements Replaces;
421 auto Err = Replaces.add(Replacement("x.cc", 10, 5, "a"));
422 EXPECT_TRUE(!Err);
423 llvm::consumeError(std::move(Err));
424 Err = Replaces.add(Replacement("x.cc", 8, 2, "a"));
425 EXPECT_TRUE(!Err);
426 llvm::consumeError(std::move(Err));
427 Err = Replaces.add(Replacement("x.cc", 10, 0, "b"));
428 EXPECT_TRUE(!Err);
429 llvm::consumeError(std::move(Err));
Manuel Klimek16c6d0a2016-08-03 15:12:00 +0000430}
431
Manuel Klimek3f001342012-05-23 16:29:20 +0000432TEST_F(ReplacementTest, CanApplyReplacements) {
433 FileID ID = Context.createInMemoryFile("input.cpp",
434 "line1\nline2\nline3\nline4");
Eric Liu40ef2fb2016-08-01 10:16:37 +0000435 Replacements Replaces =
436 toReplacements({Replacement(Context.Sources,
437 Context.getLocation(ID, 2, 1), 5, "replaced"),
438 Replacement(Context.Sources,
439 Context.getLocation(ID, 3, 1), 5, "other")});
Edwin Vane349e1c12013-08-13 17:38:19 +0000440 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
441 EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));
442}
443
Eric Liu9df9b6f2016-09-19 08:40:42 +0000444// Verifies that replacement/deletion is applied before insertion at the same
445// offset.
446TEST_F(ReplacementTest, InsertAndDelete) {
447 FileID ID = Context.createInMemoryFile("input.cpp",
448 "line1\nline2\nline3\nline4");
449 Replacements Replaces = toReplacements(
450 {Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 6, ""),
451 Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 0,
452 "other\n")});
453 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
454 EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID));
455}
456
457TEST_F(ReplacementTest, AdjacentReplacements) {
458 FileID ID = Context.createInMemoryFile("input.cpp",
459 "ab");
460 Replacements Replaces = toReplacements(
461 {Replacement(Context.Sources, Context.getLocation(ID, 1, 1), 1, "x"),
462 Replacement(Context.Sources, Context.getLocation(ID, 1, 2), 1, "y")});
463 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
464 EXPECT_EQ("xy", Context.getRewrittenText(ID));
465}
466
Eric Liu6ef82b62016-09-28 11:02:16 +0000467TEST_F(ReplacementTest, AddDuplicateReplacements) {
Manuel Klimek3f001342012-05-23 16:29:20 +0000468 FileID ID = Context.createInMemoryFile("input.cpp",
469 "line1\nline2\nline3\nline4");
Eric Liu40ef2fb2016-08-01 10:16:37 +0000470 auto Replaces = toReplacements({Replacement(
471 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});
472
473 auto Err = Replaces.add(Replacement(
474 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced"));
Eric Liu6ef82b62016-09-28 11:02:16 +0000475 EXPECT_TRUE(!Err);
Eric Liu40ef2fb2016-08-01 10:16:37 +0000476 llvm::consumeError(std::move(Err));
477
478 Err = Replaces.add(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
479 5, "replaced"));
Eric Liu6ef82b62016-09-28 11:02:16 +0000480 EXPECT_TRUE(!Err);
Eric Liu40ef2fb2016-08-01 10:16:37 +0000481 llvm::consumeError(std::move(Err));
482
Manuel Klimek3f001342012-05-23 16:29:20 +0000483 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
484 EXPECT_EQ("line1\nreplaced\nline3\nline4", Context.getRewrittenText(ID));
485}
486
Eric Liu6ef82b62016-09-28 11:02:16 +0000487TEST_F(ReplacementTest, FailOrderDependentReplacements) {
488 FileID ID = Context.createInMemoryFile("input.cpp",
489 "line1\nline2\nline3\nline4");
490 auto Replaces = toReplacements({Replacement(
491 Context.Sources, Context.getLocation(ID, 2, 1), 5, "other")});
492
Eric Liue86a5f42016-11-22 13:46:42 +0000493 Replacement ConflictReplacement(Context.Sources,
494 Context.getLocation(ID, 2, 1), 5, "rehto");
495 auto Err = Replaces.add(ConflictReplacement);
496 EXPECT_TRUE(checkReplacementError(std::move(Err),
497 replacement_error::overlap_conflict,
498 *Replaces.begin(), ConflictReplacement));
Eric Liu6ef82b62016-09-28 11:02:16 +0000499
500 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
501 EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID));
502}
503
Eric Liu40ef2fb2016-08-01 10:16:37 +0000504TEST_F(ReplacementTest, InvalidSourceLocationFailsApplyAll) {
505 Replacements Replaces =
506 toReplacements({Replacement(Context.Sources, SourceLocation(), 5, "2")});
507
Manuel Klimek3f001342012-05-23 16:29:20 +0000508 EXPECT_FALSE(applyAllReplacements(Replaces, Context.Rewrite));
Manuel Klimek3f001342012-05-23 16:29:20 +0000509}
510
Eric Liu4c1ef97a2016-03-29 16:31:53 +0000511TEST_F(ReplacementTest, MultipleFilesReplaceAndFormat) {
512 // Column limit is 20.
513 std::string Code1 = "Long *a =\n"
514 " new Long();\n"
515 "long x = 1;";
516 std::string Expected1 = "auto a = new Long();\n"
517 "long x =\n"
518 " 12345678901;";
519 std::string Code2 = "int x = 123;\n"
520 "int y = 0;";
521 std::string Expected2 = "int x =\n"
522 " 1234567890123;\n"
523 "int y = 10;";
Eric Liu40ef2fb2016-08-01 10:16:37 +0000524 StringRef File1 = "format_1.cpp";
525 StringRef File2 = "format_2.cpp";
526 FileID ID1 = Context.createInMemoryFile(File1, Code1);
527 FileID ID2 = Context.createInMemoryFile(File2, Code2);
Eric Liu4c1ef97a2016-03-29 16:31:53 +0000528
Eric Liu4c1ef97a2016-03-29 16:31:53 +0000529 // Scrambled the order of replacements.
Eric Liu40ef2fb2016-08-01 10:16:37 +0000530 std::map<std::string, Replacements> FileToReplaces;
531 FileToReplaces[File1] = toReplacements(
532 {tooling::Replacement(Context.Sources, Context.getLocation(ID1, 1, 1), 6,
533 "auto "),
534 tooling::Replacement(Context.Sources, Context.getLocation(ID1, 3, 10), 1,
535 "12345678901")});
536 FileToReplaces[File2] = toReplacements(
537 {tooling::Replacement(Context.Sources, Context.getLocation(ID2, 1, 12), 0,
538 "4567890123"),
539 tooling::Replacement(Context.Sources, Context.getLocation(ID2, 2, 9), 1,
540 "10")});
541 EXPECT_TRUE(
542 formatAndApplyAllReplacements(FileToReplaces, Context.Rewrite,
543 "{BasedOnStyle: LLVM, ColumnLimit: 20}"));
Eric Liu4c1ef97a2016-03-29 16:31:53 +0000544 EXPECT_EQ(Expected1, Context.getRewrittenText(ID1));
545 EXPECT_EQ(Expected2, Context.getRewrittenText(ID2));
546}
547
Daniel Jasper2a250b82013-05-21 12:21:39 +0000548TEST(ShiftedCodePositionTest, FindsNewCodePosition) {
Eric Liu40ef2fb2016-08-01 10:16:37 +0000549 Replacements Replaces =
550 toReplacements({Replacement("", 0, 1, ""), Replacement("", 4, 3, " ")});
Daniel Jasper2a250b82013-05-21 12:21:39 +0000551 // Assume ' int i;' is turned into 'int i;' and cursor is located at '|'.
Eric Liu40ef2fb2016-08-01 10:16:37 +0000552 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0)); // |int i;
553 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(1)); // |nt i;
554 EXPECT_EQ(1u, Replaces.getShiftedCodePosition(2)); // i|t i;
555 EXPECT_EQ(2u, Replaces.getShiftedCodePosition(3)); // in| i;
556 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(4)); // int| i;
557 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(5)); // int | i;
558 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(6)); // int |i;
559 EXPECT_EQ(4u, Replaces.getShiftedCodePosition(7)); // int |;
560 EXPECT_EQ(5u, Replaces.getShiftedCodePosition(8)); // int i|
Edwin Vane18e503c2013-08-27 15:44:26 +0000561}
562
Daniel Jasper2a250b82013-05-21 12:21:39 +0000563TEST(ShiftedCodePositionTest, FindsNewCodePositionWithInserts) {
Eric Liu40ef2fb2016-08-01 10:16:37 +0000564 Replacements Replaces = toReplacements({Replacement("", 4, 0, "\"\n\"")});
Daniel Jasper2a250b82013-05-21 12:21:39 +0000565 // Assume '"12345678"' is turned into '"1234"\n"5678"'.
Eric Liu40ef2fb2016-08-01 10:16:37 +0000566 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(3)); // "123|5678"
567 EXPECT_EQ(7u, Replaces.getShiftedCodePosition(4)); // "1234|678"
568 EXPECT_EQ(8u, Replaces.getShiftedCodePosition(5)); // "12345|78"
Daniel Jasper3fed9452015-11-23 08:33:48 +0000569}
570
571TEST(ShiftedCodePositionTest, FindsNewCodePositionInReplacedText) {
Daniel Jasper3fed9452015-11-23 08:33:48 +0000572 // Replace the first four characters with "abcd".
Eric Liu40ef2fb2016-08-01 10:16:37 +0000573 auto Replaces = toReplacements({Replacement("", 0, 4, "abcd")});
Daniel Jasper3fed9452015-11-23 08:33:48 +0000574 for (unsigned i = 0; i < 3; ++i)
Eric Liu40ef2fb2016-08-01 10:16:37 +0000575 EXPECT_EQ(i, Replaces.getShiftedCodePosition(i));
576}
577
578TEST(ShiftedCodePositionTest, NoReplacementText) {
579 Replacements Replaces = toReplacements({Replacement("", 0, 42, "")});
580 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0));
581 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(39));
582 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(45));
583 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(42));
Daniel Jasper2a250b82013-05-21 12:21:39 +0000584}
585
Manuel Klimek3f001342012-05-23 16:29:20 +0000586class FlushRewrittenFilesTest : public ::testing::Test {
Rafael Espindola641c6a12013-06-26 15:01:50 +0000587public:
588 FlushRewrittenFilesTest() {}
Manuel Klimek3f001342012-05-23 16:29:20 +0000589
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000590 ~FlushRewrittenFilesTest() override {
Rafael Espindola641c6a12013-06-26 15:01:50 +0000591 for (llvm::StringMap<std::string>::iterator I = TemporaryFiles.begin(),
592 E = TemporaryFiles.end();
593 I != E; ++I) {
594 llvm::StringRef Name = I->second;
Rafael Espindolac0809172014-06-12 14:02:15 +0000595 std::error_code EC = llvm::sys::fs::remove(Name);
Rafael Espindola641c6a12013-06-26 15:01:50 +0000596 (void)EC;
597 assert(!EC);
598 }
Manuel Klimek3f001342012-05-23 16:29:20 +0000599 }
600
601 FileID createFile(llvm::StringRef Name, llvm::StringRef Content) {
Rafael Espindola641c6a12013-06-26 15:01:50 +0000602 SmallString<1024> Path;
603 int FD;
Rafael Espindolac0809172014-06-12 14:02:15 +0000604 std::error_code EC = llvm::sys::fs::createTemporaryFile(Name, "", FD, Path);
Rafael Espindola641c6a12013-06-26 15:01:50 +0000605 assert(!EC);
606 (void)EC;
607
608 llvm::raw_fd_ostream OutStream(FD, true);
Manuel Klimek3f001342012-05-23 16:29:20 +0000609 OutStream << Content;
610 OutStream.close();
611 const FileEntry *File = Context.Files.getFile(Path);
Craig Topper416fa342014-06-08 08:38:12 +0000612 assert(File != nullptr);
Rafael Espindola641c6a12013-06-26 15:01:50 +0000613
David Blaikie13156b62014-11-19 03:06:06 +0000614 StringRef Found =
615 TemporaryFiles.insert(std::make_pair(Name, Path.str())).first->second;
Rafael Espindola641c6a12013-06-26 15:01:50 +0000616 assert(Found == Path);
617 (void)Found;
Manuel Klimek3f001342012-05-23 16:29:20 +0000618 return Context.Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
619 }
620
621 std::string getFileContentFromDisk(llvm::StringRef Name) {
Rafael Espindola641c6a12013-06-26 15:01:50 +0000622 std::string Path = TemporaryFiles.lookup(Name);
623 assert(!Path.empty());
Manuel Klimek3f001342012-05-23 16:29:20 +0000624 // We need to read directly from the FileManager without relaying through
625 // a FileEntry, as otherwise we'd read through an already opened file
626 // descriptor, which might not see the changes made.
627 // FIXME: Figure out whether there is a way to get the SourceManger to
628 // reopen the file.
Benjamin Kramera8857962014-10-26 22:44:13 +0000629 auto FileBuffer = Context.Files.getBufferForFile(Path);
630 return (*FileBuffer)->getBuffer();
Manuel Klimek3f001342012-05-23 16:29:20 +0000631 }
632
Rafael Espindola641c6a12013-06-26 15:01:50 +0000633 llvm::StringMap<std::string> TemporaryFiles;
Manuel Klimek3f001342012-05-23 16:29:20 +0000634 RewriterTestContext Context;
635};
636
637TEST_F(FlushRewrittenFilesTest, StoresChangesOnDisk) {
638 FileID ID = createFile("input.cpp", "line1\nline2\nline3\nline4");
Eric Liu40ef2fb2016-08-01 10:16:37 +0000639 Replacements Replaces = toReplacements({Replacement(
640 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});
Manuel Klimek3f001342012-05-23 16:29:20 +0000641 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
642 EXPECT_FALSE(Context.Rewrite.overwriteChangedFiles());
643 EXPECT_EQ("line1\nreplaced\nline3\nline4",
644 getFileContentFromDisk("input.cpp"));
645}
646
647namespace {
648template <typename T>
649class TestVisitor : public clang::RecursiveASTVisitor<T> {
650public:
651 bool runOver(StringRef Code) {
652 return runToolOnCode(new TestAction(this), Code);
653 }
654
655protected:
656 clang::SourceManager *SM;
Manuel Klimek94a89232015-06-03 13:10:41 +0000657 clang::ASTContext *Context;
Manuel Klimek3f001342012-05-23 16:29:20 +0000658
659private:
660 class FindConsumer : public clang::ASTConsumer {
661 public:
662 FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {}
663
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000664 void HandleTranslationUnit(clang::ASTContext &Context) override {
Manuel Klimek3f001342012-05-23 16:29:20 +0000665 Visitor->TraverseDecl(Context.getTranslationUnitDecl());
666 }
667
668 private:
669 TestVisitor *Visitor;
670 };
671
672 class TestAction : public clang::ASTFrontendAction {
673 public:
674 TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
675
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000676 std::unique_ptr<clang::ASTConsumer>
David Blaikie6beb6aa2014-08-10 19:56:51 +0000677 CreateASTConsumer(clang::CompilerInstance &compiler,
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000678 llvm::StringRef dummy) override {
Manuel Klimek3f001342012-05-23 16:29:20 +0000679 Visitor->SM = &compiler.getSourceManager();
Manuel Klimek94a89232015-06-03 13:10:41 +0000680 Visitor->Context = &compiler.getASTContext();
Manuel Klimek3f001342012-05-23 16:29:20 +0000681 /// TestConsumer will be deleted by the framework calling us.
David Blaikie6beb6aa2014-08-10 19:56:51 +0000682 return llvm::make_unique<FindConsumer>(Visitor);
Manuel Klimek3f001342012-05-23 16:29:20 +0000683 }
684
685 private:
686 TestVisitor *Visitor;
687 };
688};
689} // end namespace
690
691void expectReplacementAt(const Replacement &Replace,
692 StringRef File, unsigned Offset, unsigned Length) {
693 ASSERT_TRUE(Replace.isApplicable());
694 EXPECT_EQ(File, Replace.getFilePath());
695 EXPECT_EQ(Offset, Replace.getOffset());
696 EXPECT_EQ(Length, Replace.getLength());
697}
698
699class ClassDeclXVisitor : public TestVisitor<ClassDeclXVisitor> {
700public:
701 bool VisitCXXRecordDecl(CXXRecordDecl *Record) {
702 if (Record->getName() == "X") {
703 Replace = Replacement(*SM, Record, "");
704 }
705 return true;
706 }
707 Replacement Replace;
708};
709
710TEST(Replacement, CanBeConstructedFromNode) {
711 ClassDeclXVisitor ClassDeclX;
712 EXPECT_TRUE(ClassDeclX.runOver(" class X;"));
713 expectReplacementAt(ClassDeclX.Replace, "input.cc", 5, 7);
714}
715
716TEST(Replacement, ReplacesAtSpellingLocation) {
717 ClassDeclXVisitor ClassDeclX;
718 EXPECT_TRUE(ClassDeclX.runOver("#define A(Y) Y\nA(class X);"));
719 expectReplacementAt(ClassDeclX.Replace, "input.cc", 17, 7);
720}
721
722class CallToFVisitor : public TestVisitor<CallToFVisitor> {
723public:
724 bool VisitCallExpr(CallExpr *Call) {
725 if (Call->getDirectCallee()->getName() == "F") {
726 Replace = Replacement(*SM, Call, "");
727 }
728 return true;
729 }
730 Replacement Replace;
731};
732
733TEST(Replacement, FunctionCall) {
734 CallToFVisitor CallToF;
735 EXPECT_TRUE(CallToF.runOver("void F(); void G() { F(); }"));
736 expectReplacementAt(CallToF.Replace, "input.cc", 21, 3);
737}
738
739TEST(Replacement, TemplatedFunctionCall) {
740 CallToFVisitor CallToF;
741 EXPECT_TRUE(CallToF.runOver(
742 "template <typename T> void F(); void G() { F<int>(); }"));
743 expectReplacementAt(CallToF.Replace, "input.cc", 43, 8);
744}
745
Manuel Klimek94a89232015-06-03 13:10:41 +0000746class NestedNameSpecifierAVisitor
747 : public TestVisitor<NestedNameSpecifierAVisitor> {
748public:
749 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLoc) {
750 if (NNSLoc.getNestedNameSpecifier()) {
751 if (const NamespaceDecl* NS = NNSLoc.getNestedNameSpecifier()->getAsNamespace()) {
752 if (NS->getName() == "a") {
753 Replace = Replacement(*SM, &NNSLoc, "", Context->getLangOpts());
754 }
755 }
756 }
757 return TestVisitor<NestedNameSpecifierAVisitor>::TraverseNestedNameSpecifierLoc(
758 NNSLoc);
759 }
760 Replacement Replace;
761};
762
763TEST(Replacement, ColonColon) {
764 NestedNameSpecifierAVisitor VisitNNSA;
765 EXPECT_TRUE(VisitNNSA.runOver("namespace a { void f() { ::a::f(); } }"));
766 expectReplacementAt(VisitNNSA.Replace, "input.cc", 25, 5);
767}
768
Manuel Klimekdce23472013-07-19 12:12:36 +0000769TEST(Range, overlaps) {
770 EXPECT_TRUE(Range(10, 10).overlapsWith(Range(0, 11)));
771 EXPECT_TRUE(Range(0, 11).overlapsWith(Range(10, 10)));
772 EXPECT_FALSE(Range(10, 10).overlapsWith(Range(0, 10)));
773 EXPECT_FALSE(Range(0, 10).overlapsWith(Range(10, 10)));
774 EXPECT_TRUE(Range(0, 10).overlapsWith(Range(2, 6)));
Edwin Vanec5148482013-08-13 18:11:16 +0000775 EXPECT_TRUE(Range(2, 6).overlapsWith(Range(0, 10)));
Manuel Klimekdce23472013-07-19 12:12:36 +0000776}
777
778TEST(Range, contains) {
779 EXPECT_TRUE(Range(0, 10).contains(Range(0, 10)));
780 EXPECT_TRUE(Range(0, 10).contains(Range(2, 6)));
781 EXPECT_FALSE(Range(2, 6).contains(Range(0, 10)));
782 EXPECT_FALSE(Range(0, 10).contains(Range(0, 11)));
783}
784
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000785TEST(Range, CalculateRangesOfReplacements) {
786 // Before: aaaabbbbbbz
787 // After : bbbbbbzzzzzzoooooooooooooooo
Eric Liu40ef2fb2016-08-01 10:16:37 +0000788 Replacements Replaces = toReplacements(
789 {Replacement("foo", 0, 4, ""), Replacement("foo", 10, 1, "zzzzzz"),
790 Replacement("foo", 11, 0, "oooooooooooooooo")});
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000791
Eric Liu40ef2fb2016-08-01 10:16:37 +0000792 std::vector<Range> Ranges = Replaces.getAffectedRanges();
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000793
Eric Liu8b636db2016-06-21 17:56:31 +0000794 EXPECT_EQ(2ul, Ranges.size());
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000795 EXPECT_TRUE(Ranges[0].getOffset() == 0);
796 EXPECT_TRUE(Ranges[0].getLength() == 0);
797 EXPECT_TRUE(Ranges[1].getOffset() == 6);
Eric Liu8b636db2016-06-21 17:56:31 +0000798 EXPECT_TRUE(Ranges[1].getLength() == 22);
799}
800
Eric Liu9df9b6f2016-09-19 08:40:42 +0000801TEST(Range, CalculateRangesOfInsertionAroundReplacement) {
802 Replacements Replaces = toReplacements(
803 {Replacement("foo", 0, 2, ""), Replacement("foo", 0, 0, "ba")});
804
805 std::vector<Range> Ranges = Replaces.getAffectedRanges();
806
807 EXPECT_EQ(1ul, Ranges.size());
808 EXPECT_EQ(0u, Ranges[0].getOffset());
809 EXPECT_EQ(2u, Ranges[0].getLength());
810}
811
Eric Liu73337f32016-08-08 13:37:39 +0000812TEST(Range, RangesAfterEmptyReplacements) {
813 std::vector<Range> Ranges = {Range(5, 6), Range(10, 5)};
814 Replacements Replaces;
815 std::vector<Range> Expected = {Range(5, 10)};
816 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
817}
818
Eric Liu8b636db2016-06-21 17:56:31 +0000819TEST(Range, RangesAfterReplacements) {
820 std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000821 Replacements Replaces = toReplacements({Replacement("foo", 0, 2, "1234")});
Eric Liu8b636db2016-06-21 17:56:31 +0000822 std::vector<Range> Expected = {Range(0, 4), Range(7, 2), Range(12, 5)};
823 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
824}
825
826TEST(Range, RangesBeforeReplacements) {
827 std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000828 Replacements Replaces = toReplacements({Replacement("foo", 20, 2, "1234")});
Eric Liu8b636db2016-06-21 17:56:31 +0000829 std::vector<Range> Expected = {Range(5, 2), Range(10, 5), Range(20, 4)};
830 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
831}
832
833TEST(Range, NotAffectedByReplacements) {
834 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000835 Replacements Replaces = toReplacements({Replacement("foo", 3, 2, "12"),
836 Replacement("foo", 12, 2, "12"),
837 Replacement("foo", 20, 5, "")});
Eric Liu8b636db2016-06-21 17:56:31 +0000838 std::vector<Range> Expected = {Range(0, 2), Range(3, 4), Range(10, 5),
839 Range(20, 0)};
840 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
841}
842
843TEST(Range, RangesWithNonOverlappingReplacements) {
844 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000845 Replacements Replaces = toReplacements({Replacement("foo", 3, 1, ""),
846 Replacement("foo", 6, 1, "123"),
847 Replacement("foo", 20, 2, "12345")});
Eric Liu8b636db2016-06-21 17:56:31 +0000848 std::vector<Range> Expected = {Range(0, 2), Range(3, 0), Range(4, 4),
849 Range(11, 5), Range(21, 5)};
850 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
851}
852
853TEST(Range, RangesWithOverlappingReplacements) {
854 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5),
855 Range(30, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000856 Replacements Replaces = toReplacements(
857 {Replacement("foo", 1, 3, ""), Replacement("foo", 6, 1, "123"),
858 Replacement("foo", 13, 3, "1"), Replacement("foo", 25, 15, "")});
Eric Liu8b636db2016-06-21 17:56:31 +0000859 std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(12, 5),
860 Range(22, 0)};
861 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
862}
863
864TEST(Range, MergeIntoOneRange) {
865 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000866 Replacements Replaces =
867 toReplacements({Replacement("foo", 1, 15, "1234567890")});
Eric Liu8b636db2016-06-21 17:56:31 +0000868 std::vector<Range> Expected = {Range(0, 15)};
869 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
870}
871
872TEST(Range, ReplacementsStartingAtRangeOffsets) {
873 std::vector<Range> Ranges = {Range(0, 2), Range(5, 5), Range(15, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000874 Replacements Replaces = toReplacements(
875 {Replacement("foo", 0, 2, "12"), Replacement("foo", 5, 1, "123"),
876 Replacement("foo", 7, 4, "12345"), Replacement("foo", 15, 10, "12")});
Eric Liu8b636db2016-06-21 17:56:31 +0000877 std::vector<Range> Expected = {Range(0, 2), Range(5, 9), Range(18, 2)};
878 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
879}
880
881TEST(Range, ReplacementsEndingAtRangeEnds) {
882 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000883 Replacements Replaces = toReplacements(
884 {Replacement("foo", 6, 1, "123"), Replacement("foo", 17, 3, "12")});
Eric Liu8b636db2016-06-21 17:56:31 +0000885 std::vector<Range> Expected = {Range(0, 2), Range(5, 4), Range(17, 4)};
886 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
887}
888
889TEST(Range, AjacentReplacements) {
890 std::vector<Range> Ranges = {Range(0, 0), Range(15, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000891 Replacements Replaces = toReplacements(
892 {Replacement("foo", 1, 2, "123"), Replacement("foo", 12, 3, "1234")});
Eric Liu8b636db2016-06-21 17:56:31 +0000893 std::vector<Range> Expected = {Range(0, 0), Range(1, 3), Range(13, 9)};
894 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
895}
896
897TEST(Range, MergeRangesAfterReplacements) {
898 std::vector<Range> Ranges = {Range(8, 0), Range(5, 2), Range(9, 0), Range(0, 1)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000899 Replacements Replaces = toReplacements({Replacement("foo", 1, 3, ""),
900 Replacement("foo", 7, 0, "12"),
901 Replacement("foo", 9, 2, "")});
902 std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(7, 0),
903 Range(8, 0)};
Eric Liu8b636db2016-06-21 17:56:31 +0000904 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000905}
906
Eric Liu40ef2fb2016-08-01 10:16:37 +0000907TEST(Range, ConflictingRangesBeforeReplacements) {
908 std::vector<Range> Ranges = {Range(8, 3), Range(5, 4), Range(9, 1)};
909 Replacements Replaces = toReplacements({Replacement("foo", 1, 3, "")});
910 std::vector<Range> Expected = {Range(1, 0), Range(2, 6)};
911 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
Edwin Vane938f6882013-08-08 13:31:14 +0000912}
913
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000914class MergeReplacementsTest : public ::testing::Test {
915protected:
916 void mergeAndTestRewrite(StringRef Code, StringRef Intermediate,
917 StringRef Result, const Replacements &First,
918 const Replacements &Second) {
919 // These are mainly to verify the test itself and make it easier to read.
Eric Liu4f8d9942016-07-11 13:53:12 +0000920 auto AfterFirst = applyAllReplacements(Code, First);
921 EXPECT_TRUE(static_cast<bool>(AfterFirst));
922 auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);
923 EXPECT_TRUE(static_cast<bool>(InSequenceRewrite));
924 EXPECT_EQ(Intermediate, *AfterFirst);
925 EXPECT_EQ(Result, *InSequenceRewrite);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000926
Eric Liu40ef2fb2016-08-01 10:16:37 +0000927 tooling::Replacements Merged = First.merge(Second);
Eric Liu4f8d9942016-07-11 13:53:12 +0000928 auto MergedRewrite = applyAllReplacements(Code, Merged);
929 EXPECT_TRUE(static_cast<bool>(MergedRewrite));
930 EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
931 if (*InSequenceRewrite != *MergedRewrite)
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000932 for (tooling::Replacement M : Merged)
933 llvm::errs() << M.getOffset() << " " << M.getLength() << " "
934 << M.getReplacementText() << "\n";
935 }
936 void mergeAndTestRewrite(StringRef Code, const Replacements &First,
937 const Replacements &Second) {
Eric Liu4f8d9942016-07-11 13:53:12 +0000938 auto AfterFirst = applyAllReplacements(Code, First);
939 EXPECT_TRUE(static_cast<bool>(AfterFirst));
940 auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);
Eric Liu40ef2fb2016-08-01 10:16:37 +0000941 tooling::Replacements Merged = First.merge(Second);
Eric Liu4f8d9942016-07-11 13:53:12 +0000942 auto MergedRewrite = applyAllReplacements(Code, Merged);
943 EXPECT_TRUE(static_cast<bool>(MergedRewrite));
944 EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
945 if (*InSequenceRewrite != *MergedRewrite)
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000946 for (tooling::Replacement M : Merged)
947 llvm::errs() << M.getOffset() << " " << M.getLength() << " "
948 << M.getReplacementText() << "\n";
949 }
950};
951
952TEST_F(MergeReplacementsTest, Offsets) {
953 mergeAndTestRewrite("aaa", "aabab", "cacabab",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000954 toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),
955 toReplacements({{"", 0, 0, "c"}, {"", 1, 0, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000956 mergeAndTestRewrite("aaa", "babaa", "babacac",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000957 toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "b"}}),
958 toReplacements({{"", 4, 0, "c"}, {"", 5, 0, "c"}}));
959 mergeAndTestRewrite("aaaa", "aaa", "aac", toReplacements({{"", 1, 1, ""}}),
960 toReplacements({{"", 2, 1, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000961
962 mergeAndTestRewrite("aa", "bbabba", "bbabcba",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000963 toReplacements({{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}),
964 toReplacements({{"", 4, 0, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000965}
966
967TEST_F(MergeReplacementsTest, Concatenations) {
968 // Basic concatenations. It is important to merge these into a single
969 // replacement to ensure the correct order.
Eric Liu40ef2fb2016-08-01 10:16:37 +0000970 {
971 auto First = toReplacements({{"", 0, 0, "a"}});
972 auto Second = toReplacements({{"", 1, 0, "b"}});
973 EXPECT_EQ(toReplacements({{"", 0, 0, "ab"}}), First.merge(Second));
974 }
975 {
976 auto First = toReplacements({{"", 0, 0, "a"}});
977 auto Second = toReplacements({{"", 0, 0, "b"}});
978 EXPECT_EQ(toReplacements({{"", 0, 0, "ba"}}), First.merge(Second));
979 }
980 mergeAndTestRewrite("", "a", "ab", toReplacements({{"", 0, 0, "a"}}),
981 toReplacements({{"", 1, 0, "b"}}));
982 mergeAndTestRewrite("", "a", "ba", toReplacements({{"", 0, 0, "a"}}),
983 toReplacements({{"", 0, 0, "b"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000984}
985
986TEST_F(MergeReplacementsTest, NotChangingLengths) {
Eric Liu40ef2fb2016-08-01 10:16:37 +0000987 mergeAndTestRewrite("aaaa", "abba", "acca",
988 toReplacements({{"", 1, 2, "bb"}}),
989 toReplacements({{"", 1, 2, "cc"}}));
990 mergeAndTestRewrite("aaaa", "abba", "abcc",
991 toReplacements({{"", 1, 2, "bb"}}),
992 toReplacements({{"", 2, 2, "cc"}}));
993 mergeAndTestRewrite("aaaa", "abba", "ccba",
994 toReplacements({{"", 1, 2, "bb"}}),
995 toReplacements({{"", 0, 2, "cc"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000996 mergeAndTestRewrite("aaaaaa", "abbdda", "abccda",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000997 toReplacements({{"", 1, 2, "bb"}, {"", 3, 2, "dd"}}),
998 toReplacements({{"", 2, 2, "cc"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000999}
1000
1001TEST_F(MergeReplacementsTest, OverlappingRanges) {
1002 mergeAndTestRewrite("aaa", "bbd", "bcbcd",
Eric Liu40ef2fb2016-08-01 10:16:37 +00001003 toReplacements({{"", 0, 1, "bb"}, {"", 1, 2, "d"}}),
1004 toReplacements({{"", 1, 0, "c"}, {"", 2, 0, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001005
Eric Liu40ef2fb2016-08-01 10:16:37 +00001006 mergeAndTestRewrite("aaaa", "aabbaa", "acccca",
1007 toReplacements({{"", 2, 0, "bb"}}),
1008 toReplacements({{"", 1, 4, "cccc"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001009 mergeAndTestRewrite("aaaa", "aababa", "acccca",
Eric Liu40ef2fb2016-08-01 10:16:37 +00001010 toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),
1011 toReplacements({{"", 1, 4, "cccc"}}));
1012 mergeAndTestRewrite("aaaaaa", "abbbba", "abba",
1013 toReplacements({{"", 1, 4, "bbbb"}}),
1014 toReplacements({{"", 2, 2, ""}}));
1015 mergeAndTestRewrite("aaaa", "aa", "cc",
1016 toReplacements({{"", 1, 1, ""}, {"", 2, 1, ""}}),
1017 toReplacements({{"", 0, 2, "cc"}}));
1018 mergeAndTestRewrite("aa", "abbba", "abcbcba",
1019 toReplacements({{"", 1, 0, "bbb"}}),
1020 toReplacements({{"", 2, 0, "c"}, {"", 3, 0, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001021
Eric Liu40ef2fb2016-08-01 10:16:37 +00001022 mergeAndTestRewrite(
1023 "aaa", "abbab", "ccdd",
1024 toReplacements({{"", 0, 1, ""}, {"", 2, 0, "bb"}, {"", 3, 0, "b"}}),
1025 toReplacements({{"", 0, 2, "cc"}, {"", 2, 3, "dd"}}));
1026 mergeAndTestRewrite(
1027 "aa", "babbab", "ccdd",
1028 toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "bb"}, {"", 2, 0, "b"}}),
1029 toReplacements({{"", 0, 3, "cc"}, {"", 3, 3, "dd"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +00001030}
1031
Eric Liucf2913c2016-11-07 06:08:23 +00001032TEST(DeduplicateByFileTest, PathsWithDots) {
Eric Liucefe7632016-10-14 09:32:06 +00001033 std::map<std::string, Replacements> FileToReplaces;
Eric Liucf2913c2016-11-07 06:08:23 +00001034 llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> VFS(
1035 new vfs::InMemoryFileSystem());
Eric Liu6b3a7cc2016-11-07 18:40:41 +00001036 FileManager FileMgr(FileSystemOptions(), VFS);
Eric Liuc45343e2016-10-14 10:10:26 +00001037#if !defined(LLVM_ON_WIN32)
Eric Liucf2913c2016-11-07 06:08:23 +00001038 StringRef Path1 = "a/b/.././c.h";
1039 StringRef Path2 = "a/c.h";
Eric Liuc45343e2016-10-14 10:10:26 +00001040#else
Eric Liucf2913c2016-11-07 06:08:23 +00001041 StringRef Path1 = "a\\b\\..\\.\\c.h";
1042 StringRef Path2 = "a\\c.h";
Eric Liuc45343e2016-10-14 10:10:26 +00001043#endif
Eric Liucf2913c2016-11-07 06:08:23 +00001044 EXPECT_TRUE(VFS->addFile(Path1, 0, llvm::MemoryBuffer::getMemBuffer("")));
1045 EXPECT_TRUE(VFS->addFile(Path2, 0, llvm::MemoryBuffer::getMemBuffer("")));
1046 FileToReplaces[Path1] = Replacements();
1047 FileToReplaces[Path2] = Replacements();
Eric Liu6b3a7cc2016-11-07 18:40:41 +00001048 FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces);
Eric Liucefe7632016-10-14 09:32:06 +00001049 EXPECT_EQ(1u, FileToReplaces.size());
Eric Liucf2913c2016-11-07 06:08:23 +00001050 EXPECT_EQ(Path1, FileToReplaces.begin()->first);
Eric Liucefe7632016-10-14 09:32:06 +00001051}
1052
Eric Liucf2913c2016-11-07 06:08:23 +00001053TEST(DeduplicateByFileTest, PathWithDotSlash) {
Eric Liucefe7632016-10-14 09:32:06 +00001054 std::map<std::string, Replacements> FileToReplaces;
Eric Liucf2913c2016-11-07 06:08:23 +00001055 llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> VFS(
1056 new vfs::InMemoryFileSystem());
Eric Liu6b3a7cc2016-11-07 18:40:41 +00001057 FileManager FileMgr(FileSystemOptions(), VFS);
Eric Liuc45343e2016-10-14 10:10:26 +00001058#if !defined(LLVM_ON_WIN32)
Eric Liucf2913c2016-11-07 06:08:23 +00001059 StringRef Path1 = "./a/b/c.h";
1060 StringRef Path2 = "a/b/c.h";
Eric Liuc45343e2016-10-14 10:10:26 +00001061#else
Eric Liucf2913c2016-11-07 06:08:23 +00001062 StringRef Path1 = ".\\a\\b\\c.h";
1063 StringRef Path2 = "a\\b\\c.h";
Eric Liuc45343e2016-10-14 10:10:26 +00001064#endif
Eric Liucf2913c2016-11-07 06:08:23 +00001065 EXPECT_TRUE(VFS->addFile(Path1, 0, llvm::MemoryBuffer::getMemBuffer("")));
1066 EXPECT_TRUE(VFS->addFile(Path2, 0, llvm::MemoryBuffer::getMemBuffer("")));
1067 FileToReplaces[Path1] = Replacements();
1068 FileToReplaces[Path2] = Replacements();
Eric Liu6b3a7cc2016-11-07 18:40:41 +00001069 FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces);
Eric Liucefe7632016-10-14 09:32:06 +00001070 EXPECT_EQ(1u, FileToReplaces.size());
Eric Liucf2913c2016-11-07 06:08:23 +00001071 EXPECT_EQ(Path1, FileToReplaces.begin()->first);
1072}
1073
1074TEST(DeduplicateByFileTest, NonExistingFilePath) {
1075 std::map<std::string, Replacements> FileToReplaces;
1076 llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> VFS(
1077 new vfs::InMemoryFileSystem());
Eric Liu6b3a7cc2016-11-07 18:40:41 +00001078 FileManager FileMgr(FileSystemOptions(), VFS);
Eric Liuc45343e2016-10-14 10:10:26 +00001079#if !defined(LLVM_ON_WIN32)
Eric Liucf2913c2016-11-07 06:08:23 +00001080 StringRef Path1 = "./a/b/c.h";
1081 StringRef Path2 = "a/b/c.h";
Eric Liuc45343e2016-10-14 10:10:26 +00001082#else
Eric Liucf2913c2016-11-07 06:08:23 +00001083 StringRef Path1 = ".\\a\\b\\c.h";
1084 StringRef Path2 = "a\\b\\c.h";
Eric Liuc45343e2016-10-14 10:10:26 +00001085#endif
Eric Liucf2913c2016-11-07 06:08:23 +00001086 FileToReplaces[Path1] = Replacements();
1087 FileToReplaces[Path2] = Replacements();
Eric Liu6b3a7cc2016-11-07 18:40:41 +00001088 FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces);
Eric Liucf2913c2016-11-07 06:08:23 +00001089 EXPECT_TRUE(FileToReplaces.empty());
Eric Liucefe7632016-10-14 09:32:06 +00001090}
1091
Manuel Klimek3f001342012-05-23 16:29:20 +00001092} // end namespace tooling
1093} // end namespace clang